-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FEATURE REQUEST] Logger usage outside HTTP context #803
Comments
Desired behavior is not supported at the moment. You can try any hacks (as presented above) to make it work but on your own risk. This is not tested and not supported. For this feature we need something similar to Will change this issue to feature request. |
logger.assign
when not inside HTTP context
This comment was marked as off-topic.
This comment was marked as off-topic.
OK, in next month or two I'm going to investigate if it's possible to make such feature work with different microservices' transports including custom strategies. For implementing this feature in a clear way we need middlewares for microservices to be landed in nest. Until then this solution could be used. |
@iamolegga consider setting up a bounty program. I'd be willing to contribute funding for you to do this if you'd prefer to handle it yourself. |
@KieronWiltshire answering your question from different issue Some thought on design for this feature: I believe the configuration for microservices should be as close as possible to the configuration of Existing
Maybe some extra parameters could be added? Maybe this should be done in different npm package and reused here, the same as |
@iamolegga to be honest... I'm not sure why this approach was even taken. Surely it would've just made sense to pass the pinojs parameters through the module and allow fully interoperability with the official pinojs package. Maybe some of your thoughts on this initial implementation would help me understand more here. |
I'm ok to handle it by myself, but this needs time to make a good API for end-users and good internal design. So far due to personal reasons I'm not able to invest such time in this feature not in working hours, I hope for your understanding. But to work on this in working hours this needs to be prioritized on my current project where we are using this library, and I believe won't happen in the nearest future as we are building and starting MVP at the moment. Answering your question: thank you for the suggestion, but it won't work as this is not about money but time. Anyway if someone wants to thank me for the work that's already done in this library please consider donating to Ukraine by the links in docs header 🙏
sorry, didn't get what do you mean. If you have a better solution you are more than welcome to fork it or open PR |
@iamolegga sorry, didn't mean to insult. I'm glad you've created this project, just looking to improve on what you've already built.
Basically... this package assumes the logging through HTTP or now at this point, microservice, but what about during queue workers etc... what I'm saying is, wouldn't it make more sense to just support pinojs as the module itself, or even better allow the passing of a pinojs instance from Would you like to converse over something like discord for this? or keep it here? |
@KieronWiltshire please keep the conversation here, or provide a summary in case conversation would take place somewhere else. I would like to know where this is going as well :) |
no worries 🙂
Sure, queue workers you mean
could you please describe more on this? What API are you expecting?
agree with @mentos1386 let's keep it here for now |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
I'm not sure why this answer is marked as off-topic, but this is the ideal solution. I do the following:
|
Hey @iamolegga any update on this? :) Or any recommended workaround? |
My current workaround: Using @withLoggerContext
foo() { Here is the code for import { Store, storage } from 'nestjs-pino/storage';
import logger from './pino-logger-instance'; // this should be the same pino instance nestjs-pino uses
export const withLoggerContext: MethodDecorator = (
target,
propertyKey,
descriptor,
) => {
const methodFunc = descriptor.value;
if (!methodFunc) {
return;
}
const newMethodFunc = function (...args) {
// @ts-expect-error
storage.run(new Store(logger.child({})), () => methodFunc.call(this, args));
};
// @ts-expect-error
descriptor.value = newMethodFunc;
}; |
Here is a version of import { Store, storage } from 'nestjs-pino/storage';
import rootPinoLogger from './pino-logger-instance'; // this should be the same pino instance nestjs-pino uses
export function WithLoggerContext() {
return function (
target,
key: string | symbol,
descriptor: PropertyDescriptor
) {
const methodFunc = descriptor.value;
if (!methodFunc) {
return descriptor;
}
if (methodFunc.constructor.name === 'AsyncFunction') {
descriptor.value = async function (...args) {
return storage.run(new Store(rootPinoLogger.child({})), async () =>
methodFunc.apply(this, args)
);
};
} else {
descriptor.value = function (...args) {
return storage.run(new Store(rootPinoLogger.child({})), () =>
methodFunc.apply(this, args)
);
};
}
return descriptor;
};
} |
can you share import rootPinoLogger from './pino-logger-instance'; |
@conioX you can just create your logger instance like this: pino(
{
level: 'debug',
transport:
process.env.NODE_ENV !== 'production'
? { target: 'pino-pretty' }
: undefined,
},
stream,
) |
Hello, I also have this issue with my application which is a nestjs REST API but also use nest-js commander to launch some scripts within the same codebase. And I wanted to use the same logger for both commander and the REST API and to be able to use logger.assign. I found a solution which seems a bit complex but works then transparently. I extend PinoLogger to override Logger.assign and Logger.logger to use In details, here are the three files: // logger.service.ts
import { Injectable, Inject } from '@nestjs/common';
import { ClsService } from 'nestjs-cls';
import { PinoLogger, Params, PARAMS_PROVIDER_TOKEN } from 'nestjs-pino';
import { type Logger, type Bindings } from 'pino';
@Injectable()
export class LoggerService extends PinoLogger {
constructor(
@Inject(PARAMS_PROVIDER_TOKEN) params: Params,
private readonly cls: ClsService,
) {
super(params);
}
assign(fields: Bindings) {
const logger = this.cls.get<Logger | undefined>('logger');
if (logger) {
this.cls.set('logger', logger.child(fields));
return;
}
try {
super.assign(fields);
} catch (error) {
this.warn(error);
}
}
get logger(): Logger {
const logger = this.cls.get<Logger | undefined>('logger');
if (logger) {
return logger;
}
return super.logger;
}
} // logger.module.ts
import { Global, Module } from '@nestjs/common';
import { ClsModule } from 'nestjs-cls';
import { LoggerConfig } from './logger.config';
import { LoggerService } from './logger.service';
@Global()
@Module({
providers: [LoggerService],
exports: [LoggerService],
imports: [
ClsModule.forRoot({
global: true,
}),
LoggerConfig,
],
})
export class LoggerModule {} // logger.config.ts
import { ConfigModule, ConfigService } from '@nestjs/config';
import { type Request, type Response } from 'express';
import { type IncomingMessage } from 'http';
import { LoggerModule } from 'nestjs-pino';
import { v4 as uuidv4 } from 'uuid';
const customReceivedMessage = (req: IncomingMessage) => {
const { method, url } = req;
return `[Request] ${method} ${url}`;
};
const customSuccessMessage = (
req: IncomingMessage,
res: Response,
responseTime: number,
) => {
const { method, url } = req;
const { statusCode } = res;
return `[Response] ${method} ${url} - ${statusCode} in ${responseTime}ms`;
};
export const LoggerConfig = LoggerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => {
// We can do some await here
return {
pinoHttp: {
level: configService.get('LOG_LEVEL', 'debug'),
autoLogging: true,
base: null,
quietReqLogger: true,
genReqId: (request: Request) =>
(request.headers['x-correlation-id'] as string | undefined) ??
uuidv4(),
messageKey: 'message',
customReceivedMessage,
customSuccessMessage,
transport:
process.env.NODE_ENV !== 'production' &&
configService.get('LOG_TARGET', 'CONSOLE') === 'CONSOLE'
? {
target: 'pino-pretty',
options: {
colorize: true,
ignore:
'reqId,req.headers,req.remoteAddress,req.remotePort,pid,hostname,res.headers',
messageKey: 'message',
},
}
: undefined,
},
};
},
}); Then I can use it like that: export class Command extends CommandRunner {
constructor(
private readonly logger: LoggerService,
) {
super();
}
@UseCls({
setup(this: LaunchNangoSyncCommand, cls: ClsService) {
cls.set('logger', this.logger.logger);
},
})
async run(): Promise<void> {
this.logger.assign({
reqId: uuidV4(),
});
this.logger.info('test');
}
}
} @iamolegga Do you think I can find a way to insert |
Question
I'm trying to use
logger.assign
outside of HTTP context. Specifically, inside sqs consumer'shandleMessage
function.I figured out with the help of #788 to initiate the
storage.run
on my own. The problem was that i don't have access toreq.log
so i usedPinoLogger.root
instead. Is this supposed to be used like this?It seems to work fine. But want to make sure we won't break something in strange ways.
I guess this also relates to
@nestjs/bull
and@nestjs/microservices
are those environments supported? As they are similarly not inside HTTP context (not passing middlewares afaik).Edit: If this is a valid usage, maybe it could be wrapped in a nicer
withNestPinoContext(() => this.processMessage(message))
like function.The text was updated successfully, but these errors were encountered: