# Local logging

By default, SDKs write `info`, `warn`, and `error` logs to the console.

To send logs elsewhere—for example, to your observability or monitoring system—define a custom logging callback by setting `logsHandler` in your `createSource` options.

The `logsHandler` callback receives all log output as well as flag evaluations, experiment exposures, and analytics events, so you can forward them to your own data warehouse or analytics system. For example, you can define a callback to forward all experiment exposures and analytics events to Segment.

{% tabs %}
{% tab title="React" %}
{% code title="src/components/AppHypertuneProvider.tsx" %}

```tsx
import { LogLevel } from 'hypertune'
import { HypertuneProvider } from '../generated/hypertune.react'

export default function AppHypertuneProvider({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <HypertuneProvider
      createSourceOptions={{
        token: import.meta.env.VITE_HYPERTUNE_TOKEN!,
        logsHandler: (logs) => {
          logs.messageList.forEach(
            ({ level, message, metadata }) => {
              if (
                [LogLevel.Warn, LogLevel.Error].includes(level)
              ) {
                console.log(
                  `[Hypertune] [${level}] ${message}`,
                  metadata
                )
              }
            }
          )
          logs.eventList.forEach((event) => {
            console.log('[Hypertune] [Event]', event)
          })
          logs.exposureList.forEach((exposure) => {
            console.log('[Hypertune] [Exposure]', exposure)
          })
          logs.evaluationList.forEach((evaluation) => {
            console.log('[Hypertune] [Evaluation]', evaluation)
          })
        },
      }}
      rootArgs={{
        context: {
          environment:
            process.env.NODE_ENV === 'development'
              ? 'development'
              : 'production',
          user: {
            id: 'e23cc9a8-0287-40aa-8500-6802df91e56a',
            name: 'Example User',
            email: 'user@example.com',
          },
        },
      }}
    >
      {children}
    </HypertuneProvider>
  )
}
```

{% endcode %}
{% endtab %}

{% tab title="Node.js" %}
{% code title="src/lib/getHypertune.ts" %}

```typescript
import { LogLevel } from 'hypertune'
import { createSource } from '../generated/hypertune'

const hypertuneSource = createSource({
  token: process.env.HYPERTUNE_TOKEN!,
  logsHandler: (logs) => {
    logs.messageList.forEach(({ level, message, metadata }) => {
      if ([LogLevel.Warn, LogLevel.Error].includes(level)) {
        console.log(
          `[Hypertune] [${level}] ${message}`,
          metadata
        )
      }
    })
    logs.eventList.forEach((event) => {
      console.log('[Hypertune] [Event]', event)
    })
    logs.exposureList.forEach((exposure) => {
      console.log('[Hypertune] [Exposure]', exposure)
    })
    logs.evaluationList.forEach((evaluation) => {
      console.log('[Hypertune] [Evaluation]', evaluation)
    })
  },
})

export default async function getHypertune() {
  // Get flag updates in serverless environments
  // await hypertuneSource.initIfNeeded();

  return hypertuneSource.root({
    args: {
      context: {
        environment:
          process.env.NODE_ENV === 'development'
            ? 'development'
            : 'production',
        user: {
          id: 'e23cc9a8-0287-40aa-8500-6802df91e56a',
          name: 'Example User',
          email: 'user@example.com',
        },
      },
    },
  })
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

***

```typescript
logsHandler?: (logs: Logs) => void;

type Logs {
  messageList: Message[];
  eventList?: Event[];
  exposureList?: Exposure[];
  evaluationList?: Evaluation[];
}

export type Message = {
  level: LogLevel;
  message: string;
  metadata: object;
}

export type Event = {
  objectTypeName: string;
  payload: ObjectValue;
};

export type Exposure = {
  splitId: string;
  unitId: string;
  event: Event | null;
  assignment: SplitAssignment;
};

export type Evaluation = {
  path: string;
  value: Value;
  args: { [path: string]: ObjectValue };
  isFallback: boolean;
};

enum LogLevel {
  Debug = 'Debug',
  Error = 'Error',
  Info = 'Info',
  Warn = 'Warn'
}
```
