npm package: @servant573/nest-jaeger
Description: Jaeger middleware to request tracing for nest application
Author: Servant573
Latest version: 2.0.0

# Nest-Jaeger

```mono
                 _        _
 _ __   ___  ___| |_     (_) __ _  ___  __ _  ___ _ __
| '_ \ / _ \/ __| __|____| |/ _` |/ _ \/ _` |/ _ \ '__|
| | | |  __/\__ \ ||_____| | (_| |  __/ (_| |  __/ |
|_| |_|\___||___/\__|   _/ |\__,_|\___|\__, |\___|_|
                       |__/            |___/
```

**Jaeger middleware to request tracing for nestjs application**

## Required Reading Opentracing

To fully understand Opentracing, it's helpful to be familiar with the [OpenTracing project](http://opentracing.io) and
[terminology](http://opentracing.io/documentation/pages/spec.html) more specifically.

## Required Reading Jaeger

To fully understand Jaeger, it's helpful to be familiar with the [Jaeger project](https://www.jaegertracing.io) and [Jaeger Client for Node](https://www.npmjs.com/package/jaeger-client)

## Installation

```bash
npm i @chankamlam/nest-jaeger -S
```

## Architecture of Jaeger Server

for development
![avatar](https://www.jaegertracing.io/img/architecture-v1.png)
for prodution
![avatar](https://www.jaegertracing.io/img/architecture-v2.png)

## Build up Jaeger Server Infra locally(development env)

```bash
docker run -d -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p5775:5775/udp -p6831:6831/udp -p6832:6832/udp \
  -p5778:5778 -p16686:16686 -p14268:14268 -p9411:9411 jaegertracing/all-in-one:latest
```

## Usage

### main.ts

```ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import {JaegerInterceptor} from '@chankamlam/nest-jaeger'
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const config = {
    serviceName: 'service1-nest',
    sampler: {
      type: 'const',
      param: 1
    },
    reporter: {
      collectorEndpoint: 'http://localhost:14268/api/traces'
    },
  };                                             // required
  const options = { baggagePrefix: '-Johua-' };  // optional,you can let options={}

  // setup as global interceptor
  app.useGlobalInterceptors(new JaegerInterceptor(config,options));
  await app.listen(3000);
}
bootstrap();
```

```ts
app.useGlobalInterceptors(new JaegerInterceptor(config,options,
(req,res)=>{
  // do something here before request if you want
  req.jaeger.log('info','just for global log')
},
(req,res)=>{
  // do some thing here before response if you want
}));
```

### Controller by using JaegerInterceptor

```ts
import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { AppService } from './app.service';
import {JaegerInterceptor} from '@chankamlam/nest-jaeger';

@Controller()
export class AppController {

  @UseInterceptors(JaegerInterceptor)
  @Get('/test')
  test(){
    return 'test'
  }
}

```

### Controller except using JaegerInterceptor when binding JaegerInterceptor globally

```ts
import { Controller, Get, UseInterceptors, SetMetadata,Req } from '@nestjs/common';
import { AppService } from './app.service';
import {JaegerInterceptor} from '@chankamlam/nest-jaeger';

@Controller()
export class AppController {

  // will use JaegerInterceptor when binding JaegerInterceptor globally
  // using remote request by jaeger.axios
  @Get('/remoteRequest')
  async remoteRequest(@Req req) {
    const result = await req.jaeger.axios({ url:'xxxxxx', method:'post', data: { key: '1234' }}).then(r=>r.data)
    return result
  }

   // will use JaegerInterceptor when binding JaegerInterceptor globally
  @Get('/test')
  test(@Req req) {
    req.jaeger.setTag(req.jaeger.tags.ERROR,true)
    req.jaeger.log('error', 'err....') // jaeger object is binded after you use JaegerInterceptor globally
    return 'test'
  }

  // will not use JaegerInterceptor
  @SetMetadata('ExceptJaegerInterceptor', true)
  @Get('/except')
  test() {
    return 'test'
  }
}

```

## Lookup Request Tracing

> open url http://localhost:16686 , remember to build up the Jager Server locally first

![avatar](https://raw.githubusercontent.com/chankamlam/express-jaeger/master/pic/1.png)
![avatar](https://raw.githubusercontent.com/chankamlam/express-jaeger/master/pic/2.png)

## _config_

> for detail, pls look up to [Jaeger Client for Node](https://www.npmjs.com/package/jaeger-client)

```ts
{
  serviceName: 'string',           // required
  disable: 'boolean',
  sampler: {
    type: 'string',                // required
    param: 'number',               // required
    hostPort: 'string',
    host: 'string',
    port: 'number',
    refreshIntervalMs: 'number'
  },
  reporter: {
    logSpans: 'boolean',
    agentHost: 'string',
    agentPort: 'number',
    collectorEndpoint: 'string',   // required
    username: 'string',
    password: 'string',
    flushIntervalMs: 'number'
  },
  throttler: {
    host: 'string',
    port: 'number',
    refreshIntervalMs: 'number'
  }
}
```

## _options_

> for details, please see [Jaeger Client for Node](https://www.npmjs.com/package/jaeger-client)

```ts
{
  contextKey: 'string',
  baggagePrefix: 'string',
  metrics: 'object', // a metrics
  logger: 'object',  // a logger
  tags: 'object',    // set of key-value pairs which will be set as process-level tags on the Tracer itself.
  traceId128bit: 'boolean',
  shareRpcSpan: 'boolean',
  debugThrottler: 'boolean',
}
```

## _jaeger_

> jaeger object will bind in req when you do `app.use(jaeger(config,options))`

```ts
{
  // write the log to master span
  log        : function(name, content)

  // setup tag to master span
  setTag     : function(name, value)

  // setup mutiple tags to master span
  addTags    : function({ k1: v1, k2: v2 })

  /*
   * create a new span under parent span,
   * if parentSpan is undefine will create a new one under default master span
   */
  createSpan : function(name, parentSpan?)

  // all defined tags of opentracing which can be used
  tags       : object

  // using it to remote call service if not it will be broken the tracing to next service
  axios      : function(url, options)
}
```

### _log_

```ts
req.jaeger.log('info', '..........')
```

### _setTag_

```ts
const jaeger = req.jaeger
const tags = jaeger

// using defined tags by opentracing
jaeger.setTag(tags.ERROR, true)

// using your customize tag
jaeger.setTag('warning', true)

```

### _setTracingTag_

```ts
const jaeger = req.jaeger
jaeger.setTracingTag('waybill', 'wb-123456')
```

### _addTags_

```ts
const jaeger = req.jaeger
const tags = jaeger

// add mutiple tag one time
jaeger.addTags({ error: true, info: true })
```

### _createSpan_

```ts
// create a sub span under master span
const span = jaeger.createSpan('subSpanName')

// you also can call method of span
span.log('info', 'info......')
span.setTag('info', true)

// remember to call finish() if not there is no record send to jaeger
span.finish();
```

### _tags_

predefined tag, some come from [OpenTracing project](http://opentracing.io)

### _axios_

jaeger.axios wrap axios with tracing header, for usage detail pls look up to [axios](https://www.npmjs.com/package/axios)

## license

MIT