Skip to content
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

MULTI TRANSPORT PROBLEM IN AWS LAMBDA #2087

Open
Diego3310 opened this issue Nov 15, 2024 · 2 comments
Open

MULTI TRANSPORT PROBLEM IN AWS LAMBDA #2087

Diego3310 opened this issue Nov 15, 2024 · 2 comments

Comments

@Diego3310
Copy link

Diego3310 commented Nov 15, 2024

Hi, I am facing an issue using sync: true in my Pino multi transport configuration within an AWS Lambda function.

According to the Pino documentation, setting sync: true should make the transport operate synchronously. However, this does not seem to work as expected in my setup. Additionally, logs are not appearing correctly in CloudWatch or SQS, depending on the transport used.

Here’s the configuration I’m using for my transports:

import pino, { DestinationStream, TransportTargetOptions } from 'pino';

import { ILoggerTransportStrategy } from '../interfaces/transport-strategy.interface';
import config from '../../../../../../config/config';
import { TransportOptions } from '../../options/options';
import { GeneralTransportOptionsType, TransportOptionsType } from '../../../../../common';

/**
 * Clase que se encarga de configurar los transportes de logs
 */
export class MultiTransportStrategy implements ILoggerTransportStrategy {
  private targets: TransportTargetOptions[];

  constructor() {
    this.targets = [];
  }

  /**
   * Configura los transportes de logs
   * @param options - Opciones de configuración
   * @returns - El destino de los logs
   */
  configure(options: GeneralTransportOptionsType): DestinationStream {
    const targets: TransportOptionsType[] = config.get('log.targets') as TransportOptionsType[];

    if (targets.length === 0) {
      return pino.transport({
        targets: [TransportOptions.select('cloud', options)],
      });
    }

    for (const target of targets) {
      this.addTransport(TransportOptions.select(target, options));
    }

    const transports = pino.transport({
      targets: this.targets,
      sync: true,
    });

    this.targets = [];

    return transports;
  }

  /**
   * Añade un transporte a la lista de transportes
   * @param transport - Transporte a añadir
   */
  private addTransport(transport: TransportTargetOptions): void {
    if (transport === null || transport === undefined) {
      return;
    }

    this.targets.push(transport);
  }
}
/**
 * -  Opciones de transporte para la consola estándar.
 * @returns TransportSingleOptions
 */
export const cloudTargetOptions = (): TransportTargetOptions => {
  return {
    level: config.get('log.level'),
    target: 'pino/file',
    options: {
      destination: 1,
    },
  };
};
import build, { OnUnknown } from 'pino-abstract-transport';
import { SQSClient, SQSClientConfig, SendMessageCommand, SendMessageRequest } from '@aws-sdk/client-sqs';

/**
 * Opciones de configuración para el transporte SQS.
 */
export type SQSTransportOptionsType = {
  region?: string;
  queueUrl: string;
  messageGroupId?: string;
  sqsOptions?: SQSClientConfig;
};

/**
 * - Transporte personalizado para enviar logs a una cola de SQS
 * @param opts - Opciones de configuración
 *  @returns - Función que recibe un objeto y lo envía a la cola de SQS
 */
export default async function (opts: SQSTransportOptionsType): Promise<OnUnknown> {
  const { region = 'us-east-1', queueUrl, messageGroupId, sqsOptions } = opts;

  const sqsClient = new SQSClient({ region, ...sqsOptions });

  return build(async function (source) {
    for await (const obj of source) {
      const logMessage = JSON.stringify({ message: JSON.stringify(obj) });

      const params: SendMessageRequest = {
        QueueUrl: queueUrl,
        MessageBody: logMessage,
        MessageGroupId: messageGroupId,
      };

      try {
        const command = new SendMessageCommand(params);

        await sqsClient.send(command);
      } catch (error) {
        console.error('Error al enviar el mensaje a SQS:', error);
      }
    }
  });
}

Expected Behavior

The sync: true option should ensure synchronous operation for the transports in AWS Lambda.
Logs should appear in the destinations (e.g., SQS or CloudWatch) during the Lambda invocation.

--

Actual Behavior

The sync: true option does not make the transports synchronous.
Logs are not visible in SQS or CloudWatch.

@DominicRoyStang
Copy link

DominicRoyStang commented Nov 28, 2024

I'm experiencing the same issue. If this is intended behavior, I think docs should be clearer about the following points:

  • Is it possible to have multiple transports, and have some/all of them be synchronous?
  • Can any transport be made to run synchronously, or is there something that the transport creator needs to do to enable this functionality?

Other possibly related issue in pino-pretty: pinojs/pino-pretty#504

@mcollina
Copy link
Member

The core of this problem is that the execution model of lambda does not play well with multithreading. The solution to your issue is to:

const transport = pino.transport(...)

//right before returning the control to AWS lambda
transport.flushSync()

Hopefully this will get everything through.

Having said that, I would recommend against using asynchronous transports in lambda due to those issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants