# @stream-io/logger

> [!IMPORTANT]
> The `@stream-io/logger` package is not to be used directly but rather re-exported pre-scoped from a specific SDK.

<sub>`sdk/src/logger.ts`</sub>

```ts
import * as logger from "@stream-io/logger";

export type AvailableScopes = "coordinator" | "network" | "sfu" | "filters";

export const configureLoggers = logger.configureLoggers<AvailableScopes>;
export const getLogger = logger.getLogger<AvailableScopes>;

// re-export rest if needed
```

After that you can set up a sink and a log level for each of these scopes individually. The mechanism will use `default` scope if logger cannot find settings for the accessed scope. A "sink" is a function which gets funneled logs an SDK code produces. A sink gets a log level, message and other values we pass down to it as arguments from the SDK.

Log levels are pre-defined and are ordered by severity as such:

- trace: 0
- debug: 1
- info: 2
- warn: 3
- error: 4

For example; if you set a log level to a value `warn` for a scope `coordinator`, you will only see errors and warnings generated by the SDK for that specific scope.

## Usage

```ts
import { configureLoggers } from "@stream-io/logger";

// arbitrary logging mechanism of your choice
import SuperLogger from "./SuperLogger";

configureLoggers({
  sfu: {
    level: "error",
  },
  coordinator: {
    level: "warn",
    sink: (logLevel, message, ...rest) => {
      switch (logLevel) {
        case "warn": {
          console.warn(message, ...rest);
          break;
        }
        case "error": {
          SuperLogger.error(message, ...rest);
        }
      }
    },
  },
});
```

You can augment the settings of the `default` scope if you don't want to apply custom sinks/levels to all the SDK-defined scopes individually.

```ts
import { configureLoggers } from "@stream-io/logger";

import SuperLogger from "./SuperLogger";

configureLoggers({
  default: {
    level: "info",
    sink: (logLevel, message, ...rest) => {
      SuperLogger[logLevel](message, ...rest);
    },
  },
});
```

If you need to reset specific scopes during your application runtime to use defaults instead you can do so as follows:

```ts
import { configureLoggers } from "@stream-io/logger";

configureLoggers({
  coordinator: {
    level: null,
    sink: null,
  },
});
```

This action will only reset the `coordinator` scope and `sfu` scope will stay intact (considering previous examples). If you need to reset the defaults completely, you can do so as follows:

```ts
import { restoreDefaults } from "@stream-io/logger";

restoreDefaults();
```

This action will clear all the pre-defined settings and restore `default` scope if it has been augmented.

## Sentry Integration

Here is an example showing a basic [Sentry](https://sentry.io/welcome/) integration:

```ts
import { LogLevel, configureLoggers, Sink } from "@stream-io/logger";

import * as Sentry from "@sentry/nextjs";

const sentrySeverityByLogLevel: Record<LogLevel, Sentry.SeverityLevel> = {
  debug: "debug",
  info: "info",
  warn: "warning",
  error: "error",
};

const customSentrySink: Sink = (logLevel, message, ...rest) => {
  Sentry.captureEvent({
    level: sentrySeverityByLogLevel[logLevel],
    extra: args,
  });
};

configureLoggers({
  default: {
    sink: customSentrySink,
    level: "warn",
  },
});
```
