npm package: @karmaniverous/loggable
Description: > **This library is deprecated in favor of [@karmaniverous/controlled-proxy](https://github.com/karmaniverous/controlled-proxy), which takes a much more generic and SOLID approach to the problem. See [this article](https://karmanivero.us/blog/mixin-it-up-
Author: Jason Williscroft
Latest version: 0.1.2
Deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.

> **This library is deprecated in favor of [@karmaniverous/controlled-proxy](https://github.com/karmaniverous/controlled-proxy), which takes a much more generic and SOLID approach to the problem. See [this article](https://karmanivero.us/blog/mixin-it-up-picking-the-right-problem-to-solve/) for an analysis of the issues with the mixin approach.**

# Loggable Mixin

**Logging is an implementation decision that should be deferred as late as possible.**

When you are writing a Typescript or Javascript class, the [`Loggable`](https://docs.karmanivero.us/loggable/functions/loggable.Loggable.html) [mixin](https://medium.com/@saif.adnan/typescript-mixin-ee962be3224d) permits the consumer of your class to:

- Inject a preferred logging system into your class, so the logs generated by your class will be consistent with those generated by the rest of the applicaion.

- Decide at runtime what level of logging your class should produce.

<!-- TYPEDOC_EXCLUDE -->

> [API Documentation](https://docs.karmanivero.us/loggable/) • [CHANGELOG](https://github.com/karmaniverous/loggable/tree/main/CHANGELOG.md)

<!-- /TYPEDOC_EXCLUDE -->

## Installation

```bash
npm i @karmaniverous/loggable
```

## Default Use Case

By default, [`Loggable`](https://docs.karmanivero.us/loggable/functions/loggable.Loggable.html) uses the `console` logger and disables `debug` logs.

```ts
import { Loggable } from '@karmaniverous/loggable';

// Defaults to console logger & disables debug logs.
class MyClass extends Loggable() {
  myMethod() {
    this.logger.debug('debug log');
    this.logger.info('info log');
  }
}

const myInstance = new MyClass();

// By default, disables debug logs.
myInstance.myMethod();
// info log

// Change disabled logger endpoints on the fly.
myInstance.loggableOptions.disabled = ['info'];
myInstance.myMethod();
// debug log

// Use the instance logger directly.
myInstance.logger.debug('debug log');
myInstance.logger.info('info log');
// debug log

// Set `enableAll` to `true` to ignore disabled endpoints.
myInstance.loggableOptions.enableAll = true;
myInstance.myMethod();
// debug log
// info log
```

## Custom Base Class, Logger & Options

You can inject a custom logger into a custom base class with custom options.

```ts
import { Loggable } from '@karmaniverous/loggable';
import winston from 'winston';

class MyBaseClass {
  protected repeat(message: string, times: number) {
    return Array.from({ length: times })
      .map(() => message)
      .join(' ');
  }
}

// Custom base class, logger & options.
class MyClass extends Loggable(MyBaseClass, winston, {
  disabled: ['debug', 'info'],
}) {
  myMethod() {
    this.logger.debug(this.repeat('debug log', 2));
    this.logger.info(this.repeat('info log', 2));
    this.logger.error(this.repeat('error log', 2));
  }
}

const myInstance = new MyClass();

myInstance.myMethod();
// error log error log <-- winston logger!
```

## Generic Logger & Options

You can create a generic class that _also_ defers the choice of logger and options!

```ts
import { Loggable } from '@karmaniverous/loggable';
import winston from 'winston';

// This function returns an anonymous class that extends Loggable.
function MyGenericClass<Logger = Console>(
  logger: Logger = console as Logger,
  options: Partial<LoggableOptions> = {},
) {
  // The anonymous class extends Loggable with the provided logger & options.
  return class extends Loggable(undefined, logger, options) {
    myMethod() {
      this.logger.debug('debug log');
      this.logger.info('info log');
      this.logger.error('error log');
    }
  };
}

// Generate a winston-logged version of my class...
const MyWinstonLoggedClass = MyGenericClass(winston, {
  disabled: ['debug', 'info'],
});

// ...and instantiate it.
const myInstance = new MyWinstonLoggedClass();

myInstance.myMethod();
// error log <-- winston logger!
```

One potential gotcha here: `this.logger` will support whatever methods the provided logger has.

If you provide a logger that doesn't have a `debug` method, for example, you will get a runtime error when you try to call `this.logger.debug`. So be sure to stick to commonly supported logger method names like `debug`, `info`, and `error`!

---

Built for you with ❤️ on Bali! Find more great tools & templates on [my GitHub Profile](https://github.com/karmaniverous).