# @theorchard/ows-logger

Logger for emitting logs in specified ows format for JS and TS projects in
Orchard. In order to achieve truly universal logging, this logger was
implemented for any JS or TS projects that needs the logs to be parsed in the
same way as [python-owslogger](https://github.com/theorchard/python-owslogger)
does it.

It exposes 3 methods for use with applications -

1. createOwsLogger
2. createOwsLoggerMiddleware
3. getTimedDecorator

This package also exposes the types required to instantiate the logger.

## Install Dependencies

It is assumed you have installed the following:

-   [node](https://nodejs.org/en/download/)
-   [pnpm](https://pnpm.io/installation/)

## Running Locally

```sh
$ git clone git@github.com:theorchard/orchard-suite.git
$ cd  orchard-suite
$ pnpm install
$ cd packages/ows-logger
```

## Running tests

Tests are written using Jest.

```sh
$ pnpm test:unit
$ pnpm test
```

## Contributing

If changes are required in the package, submit a PR following the contribution
guidelines of (orchard-suite)[https://github.com/theorchard/orchard-suite].

## Examples

### Standalone Logger

The logger can be used as a independent logger in following way

#### Creating a new logger

In Javascript,

```javascript
import { createOwsLogger } from '@theorchard/ows-logger';

const opts = {
    environment: 'dev',
    loggerName: 'owslogger',
    loggerLevel: 'debug',
    serviceName: 'gateway-social-auth',
    serviceVersion: '1.0.0',
};

const logger = createOwsLogger(opts);
```

In Typescript,

```typescript
import { createOwsLogger, OwsLoggerOptions, Pino } from '@theorchard/ows-logger';

const opts: OwsLoggerOptions = {
    environment: 'dev',
    loggerName: 'owslogger',
    loggerLevel: 'debug',
    serviceName: 'gateway-social-auth',
    serviceVersion: '1.0.0',
};

const logger = createOwsLogger(opts);
```

#### Using the logger

Logger created above is now ready to send logs. Following are the types of logs you can send.

```javascript
logger.debug('This is a DEBUG log');
logger.info('This is a INFO log');
logger.notice('This is a NOTICE log');
logger.warning('This is a WARNING log');
logger.error('This is a ERROR log');
logger.critical('This is CRITICAL log');
```

#### Logging with a object

If you want to log with some extra resources, you can use pass an object to the
logger.

```javascript
const resources = { a: 1, b: 2 };
logger.info(resources, 'I am a log with RESOURCES');
```

#### Changing destination of the logs

The logger when not passed any options will emit the logs to standard output.
In order to change the location of the logs a `destination` option can be
passed in the options argument.

The destination can be any [write stream](https://nodejs.org/api/stream.html#stream_class_stream_writable) from nodejs. For better performance you
can use [pino.destination](https://getpino.io/#/docs/api?id=pino-destination)

```typescript
import { createOwsLogger, OwsLoggerOptions, Pino } from '@theorchard/ows-logger';
import stream from 'stream';

const stream = new stream.PassThrough();
const opts: OwsLoggerOptions = {
    destination: stream,
    environment: 'dev',
    loggerName: 'owslogger',
    loggerLevel: 'debug',
    serviceName: 'gateway-social-auth',
    serviceVersion: '1.0.0',
};

const logger = createOwsLogger(opts);
logger.info('I will be written to passthrough stream');
```

### Express Logger

`ows-logger` can be used as a middleware in express application for logging requests and responses. The logger is scoped per request and can be found in `res.locals.GLOBAL_LOGGER`. In order to use `owslogger` in express middleware, import `createOwsLoggerMiddleware` from `@theorchard/ows=logger`.

In your `app.ts` or `app.js`,

```javascript
import express from 'express';
import { createOwsLoggerMiddleware } from '@theorchard/ows-logger';

const app = express();
const opts = {
    environment: 'dev',
    loggerName: 'owslogger',
    serviceName: 'gateway-social-auth',
    serviceVersion: '1.0.0',
    autolog: true,
    excludePaths: ['/hello', '/health'],
};
const loggingMiddleware = createOwsLoggerMiddleware(opts);
app.use(loggingMiddleware);
```

#### Correlation Id

In order to track the request across the microservices, this logger also gives you the convinience of setting correlation id for a request if one is not already present. If one is present in the request header it reuses that.

#### Autologging

`ows-logger` gives you the functionality of autologging. You can pass in the option `autolog: true` in the options of `createOwsLoggerMiddleware` in order to get the convinience in an express application.

```javascript
import express from 'express';
import { createOwsLoggerMiddleware } from '@theorchard/ows-logger';

const app = express();
const opts = {
    environment: 'dev',
    loggerName: 'owslogger',
    serviceName: 'gateway-social-auth',
    serviceVersion: '1.0.0',
    autolog: true,
};
const loggingMiddleware = createOwsLoggerMiddleware(opts);
app.use(loggingMiddleware);
```

By doing this, you will be able to log responses to your express application. For eg.

```
200 - GET /hello
```

This log will be set in the message field of the json log.

#### Application Logging

If any application level logs need to be emitted during the processing of the request. The logger object is set in the `res.locals` object in express. It can be used in the following way -

```javascript
res.locals.logger.info('Hello world');
```

### Time Decorators

This package also provides the convinience of logging the timing of your functions in development environment.

#### Usage

```typescript
import { createOwsLogger, getTimedDecorator } from '@theorchard/ows-logger';

const logger = createOwsLogger();
const environment = process.env;
const timed = getTimedDecorator({ logger, environment });

class TestClass {
    @timed()
    testmethod1() {
        return 42;
    }
}
```

This will print the following messages when the object is instantiated and
method is invoked like -

```typescript
const t = new TestClass();
t.testmethod1();
```

Will result in -

```
{ message: "Entering `TestClass.testmethod1`" .....}
{ message: "Exiting `TestClass.testmethod1`: 1ms", ... }
```
