ForestAgent-NodeJS : How to access the context to identify user in a 3rd party tool (like Sentry)

Feature(s) impacted

I’m using the forestadmin/agent mounted on an express app (only the admin is running on this app though) and I’m setting up Sentry to monitor perf and bugs.

I want to identify the user doing the request, but I don’t understand how I can tap into the agent.

Today, I’m adding a middleware to read and decode the authorization header but maybe there’s a cleaner solution.

Context

  • Project name: Muzzo
  • Team name: Muzzo
  • Environment name: Local
  • Agent type & version:
"@forestadmin/agent": "^1.8.8",
"@forestadmin/datasource-sql": "^1.3.0",
"@forestadmin/datasource-toolkit": "^1.4.2"

Also, I’ve noticed something I still don’t understand. When I add a middleware before mounting the agent, I can see it’s executed but when I add it after mounting the agent, it doesn’t seem to be executed.

So I can’t tap into forest context after mounting it

My Setup


const myMiddlewareFactory = (message:string) => (req, res, next) => {
 console.log('middleware:', message);
 next();
}

const app = express();

app.use(myMiddlewareFactory('before')); // I see logs

await agent.mountOnExpress(app).start();

app.use(myMiddlewareFactory('after')); // can't see logs

app.listen(env.PORT);

Hey @ajubin, and welcome to our community :wave:

We do provide a way to customize log using the logger, loggerLevel, and customizeErrorMessage options with documentation here. However, there are currently no way to retrieve the user this way.

Depending on your needs, hooks could maybe also do the trick.

Also, I’ve noticed something I still don’t understand. When I add a middleware before mounting the agent, I can see it’s executed but when I add it after mounting the agent, it doesn’t seem to be executed.

Indeed, after will not be called on forest routes, but that’s related to how express middleware works.

For eg, if you add a route definition after your after middleware, you should be able to see before and after message being displayed.

Let me know if that helps.

Hi @jeffladira,

thanks for the quick answer and the explanation about forest middleware, as I’m not using them on other projects, maybe I can make silly mistakes :smile:

I’ve looked at logger, loggerLevel and customizeErrorMessage but I’m not sure if it’s the appropriate way to report error on Sentry (a monitoring tool)

For the hooks, it’s only at a collection level so it can’t do the trick in my case

Then your solution would be the cleanest we offer right now.

If you want to retrieve info from a route level, express middleware would be the best one.
If you want to retrieve error messages on sentry (Without user infos), Hooks or logger, loggerLevel and customizeErrorMessage would be the way to go.
If you want to retrieve both in a single line, then this is not currently supported, and I can push this to our product board.

Let me know :pray:

For the record, here is what I did

To identify user in Sentry

 // identify user based on jwt
  app.use((req, res, next) => {
    if (req.headers.authorization) {
      const [, jwtToken] = req.headers.authorization.split(' ');
      const decodedToken = jwt.decode(jwtToken, {
        complete: true,
      });

      if (decodedToken.payload.email) {
        Sentry.setUser({ email: decodedToken.payload.email });
      }
    }

    next();
  });

To report error in Sentry

// on createAgent function
const agent = createAgent({
  logger: (level, data, error) => {
      // Default logger copy pasted from: https://github.com/ForestAdmin/agent-nodejs/blob/95ee789933417ccde1be26c0ba587b38fd7d4264/packages/agent/src/utils/options-validator.ts#LL20C8-L20C8
      const loggerLevel = 'Info';
      const loggerPrefix = {
        Debug: '\x1b[34mdebug:\x1b[0m',
        Info: '\x1b[32minfo:\x1b[0m',
        Warn: '\x1b[33mwarning:\x1b[0m',
        Error: '\x1b[31merror:\x1b[0m',
      };
      const levels = Object.keys(loggerPrefix);
      if (levels.indexOf(level) >= levels.indexOf(loggerLevel)) {
        // eslint-disable-next-line no-console
        console.error(loggerPrefix[level], data);
      }
      // end of default logger

      if (level === 'Warn' || level === 'Error') {
        Sentry.captureException(error);
      }
    },

})
1 Like