Creating TypeScript class decorator for log correlation

275 Views Asked by At

I'm trying to create a TypeScript decorator that can be added to any class, that will create a request-scoped context that I can use to store a request ID. I've come across a couple of articles around decorators but none seem to fit my use-case.

Below is the code that I use to create the async hook, the decorator and a sample class that should be wrapped. When running the code, the actual response I receive is an empty object. The context is being lost but I'm not following why. I'm not receiving any errors or warnings.

Any suggestions would be highly appreciated.

This is the code I'm using to create the context. Calling the initContext() and getContext() functions.

import * as asyncHooks from 'async_hooks'

const contexts: any = {}

asyncHooks.createHook({
  init: (asyncId: any, type: any, triggerAsyncId: any) => {
    if (contexts[triggerAsyncId]) {
      contexts[asyncId] = contexts[triggerAsyncId]
    }
  }
}).enable()

function initContext(fn: any) {
  const asyncResource = new asyncHooks.AsyncResource('REQUEST_CONTEXT')
  return asyncResource.runInAsyncScope(() => {
    const asyncId = asyncHooks.executionAsyncId()
    contexts[asyncId] = {}
    return fn(contexts[asyncId])
  })
}

function getContext() {
  const asyncId = asyncHooks.executionAsyncId()
  return contexts[asyncId] || {}
}

export { initContext, getContext }

This is the decorator that I'm using to wrap the class with. I'm trying to create the constructor within the context of the initContext function, set the context ID and then return the new constructor.

import { initContext } from './lib/context'

function AsyncHooksContext<T extends { new(...args: any[]): {} }>(target: T) {
  return initContext((context: any) => {
    context.id = 'some-uuid-goes-here'

    return class extends target {
      constructor(...args: any[]) {
        super(...args)
      }
    }
  })
}

export { AsyncHooksContext }

This is a sample class that should be able to produce the context ID

@AsyncHooksContext
class Foo {
  public bar() {
    const context = getContext()
    console.log('This should be the context => ', { context })
  }
}

new Foo().bar()
0

There are 0 best solutions below