# @dandi/core/logging

Dandi's splits the responsibilities of logging into two primary parts:

- `Logger` is the primary interface that developers will interact with - implementations of `Logger` are used to generate
  the log entries themselves, and can draw in contextual metadata about where they are called from. An app will have a
  single `Logger` instance. If no provider for `Logger` is available, the app will use `NoopLogger` by default.

- `LogListener` implementations receive the log data generated by the `Logger`. What they do with that data depends on
  the implementation - `ConsoleLogListener`, for example, formats the log data and sends it to the program's `console`
  output. Other implementations could store the data locally, or transmit it to a remote API. An app may use any number
  of `LogListener` implementations simultaneously.

By default, this pattern is implemented using an RxJS `Subject`. The `Subject` instance is defined using the `LogStream`
injection token. The `Logger` instance calls `next()` on the `LogStream` for each log entry. `LogListener` instances
subscribe to the `LogStream` as an `Observable`.

_Note:_ The DI system in `@dandi/core` uses `Logger` internally, which is why `Logger` is part of the root `@dandi/core`
package and not `@dandi/core/logging`.

## Implementations

### Logger

#### ContexualLogger

- **Package:** [@dandi/core/logging](.)
- **Module:** `LoggingModule` in [@dandi/core/logging](.)
- Includes a reference the consuming service in the logging data

```typescript
// main.ts
import { DandiApplication } from '@dandi/core'
import { LoggingModule } from '@dandi/core/logging' // includes ContextualLogger

const container = new DandiApplication({
  providers: [
    LoggingModule,
    /* other providers */
  ],
})

// my-service.ts
import { Inject, Injectable, Logger } from '@dandi/core'

@Injectable()
export class MyService {
  constructor(@Inject(Logger) private logger: Logger) {
    this.logger.debug('Constructed!')
  }
}
```

In the above example, when the instances are created, the `ContextualLogger` instance uses the `InjectionContext` token
provided by the Dandi DI system to receive a reference to the instance of `MyService` that caused it to be created. It
then includes that reference when creating log entries like the call to `debug()`.

#### NoopLogger

- **Package:** [@dandi/core](.)
- **Module:** n/a - used as a fallback by `@dandi/core`
- As the name suggests, `NoopLogger` does not generate log entries

When no `Logger` implementation is configured, `NoopLogger` is used by default.

#### ConsoleLogListener

- **Package:** [@dandi/core/logging](.)
- **Module:** n/a
- Outputs formatted log data to the environment's `console`

Include `ConsoleLogListener` by calling the `use` method on `LoggingModule`.

```typescript
import { DandiApplication } from '@dandi/core'
import { ConsoleLogListener, LoggingModule } from '@dandi/core/logging'

const container = new DandiApplication({
  providers: [
    LoggingModule.use(ConsoleLogListener),
    /* other providers */
  ],
})
```

##### Formatting

`ConsoleLogListener` can be customized to format the log data as desired.

TODO

## API Documentation

TODO

### Logger

TODO
