Skip to content

segmentio/try-catch-finally-hooks.js

Repository files navigation

Try-catch-finally-hooks

NPM Version

This is a simple AOP-ish toolset that lets to wrap sync and async functions and class methods with hooks which let you:

  • override onTry:
    • function's input parameters
    • function's this arg
    • function itself (hook can conditionally do some extra wrapping)
  • override onCatch, onFinally:
    • function's result
    • function's error to (re-)throw
  • log, measure all of those mentioned above

It supports using as decorator, function wrapper or scope of anonymous function:

It supports typescript

It supports sync and async functions/methods

/// track.ts
export const hooks = new Hooks()
  .add(callStack)
  .add(measureDuration)
  .add(ctx => {
    console.log(`ℹ️ Action ${ctx.name} started...`)
    return {
      onFinally() {
        if(ctx.funcOutcome.error)
          console.log(`❌ Action ${ctx.name} failed with ${ctx.funcOutcome.error}. Took ${ctx.duration}ms to complete`)
        else
          console.log(`✅ Action ${ctx.name} succeed with result:${ctx.funcOutcome.result}. Took ${ctx.duration}ms to complete`)
        // you can override either result or error here
        // if you set ctx.funcOutcome.error = undefined - function will not throw error

        datadog.histogram(
          `action-${ctx.name}-duration`,
          ctx.duration,
          { tags: ['action:' + ctx.name, 'callstack:' + ctx.getCallStack().map(c => c.name).join('/')] }
        );
      },
    };
  })

export const track = hooks.create()
// myClass.ts

class MyClass{
  @track({name:'Hello world'})
  //@hooks.decor({name:'Hello world'}) //alternative
  async helloWorld(url:string)
  {
    await doing()
    await somethingLongRunning(url)
    return await andErroneous()
  }
}

// myFunc.ts


export const myFunc = track({name: 'My function'}, (param1:number)=>{   //alternative: myFunc = hooks.wrap({name:'Hello world'}, (param1...)=>{...})

    // doing something long running and risky
  step1()
  step2()
  const res = track.scope({name:'important step 3'},()=>{
    return step3(param1)
  })
  return res
})

See specs for examples