npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@dev7a/otlp-stdout-exporter

v0.1.0

Published

OpenTelemetry OTLP exporter that writes to stdout

Downloads

67

Readme

@dev7a/otlp-stdout-exporter

OpenTelemetry OTLP exporter that writes to stdout: the telemetry data is serialized using OTLP JSON or Protobuf encoding, and then written to stdout within a structured JSON object. In a AWS Lambda serverless environment, the data is captured by CloudWatch and can be consumed by the Lambda OTLP Forwarder, to be forwarded to a OTEL collector or your telemetry platform.

[!IMPORTANT] This package is highly experimental and should not be used in production. Contributions are welcome.

Features

  • Implements OTLP exporter for OpenTelemetry traces
  • Exports data to stdout in a structured JSON format
  • Supports both JSON and Protobuf formats
  • Designed for serverless environments, especially AWS Lambda
  • Configurable through environment variables
  • Support for GZIP compression
  • Base64 encoding for binary payloads

Installation

Install the package along with its peer dependencies:

# Using npm
npm install @dev7a/otlp-stdout-exporter @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/resources @opentelemetry/semantic-conventions

# Using yarn
yarn add @dev7a/otlp-stdout-exporter @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/resources @opentelemetry/semantic-conventions

# Using pnpm
pnpm add @dev7a/otlp-stdout-exporter @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/resources @opentelemetry/semantic-conventions

AWS Lambda Usage

Here's an example of using the exporter in an AWS Lambda function with distributed tracing:

const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
const { BatchSpanProcessor } = require('@opentelemetry/sdk-trace-base');
const { Resource } = require('@opentelemetry/resources');
const { ATTR_SERVICE_NAME } = require('@opentelemetry/semantic-conventions');
const { trace, SpanKind, context, propagation } = require('@opentelemetry/api');
const { StdoutOTLPExporterNode } = require('@dev7a/otlp-stdout-exporter');
const { AwsLambdaDetectorSync } = require('@opentelemetry/resource-detector-aws');
const { W3CTraceContextPropagator } = require('@opentelemetry/core');

// Set up W3C Trace Context propagator
propagation.setGlobalPropagator(new W3CTraceContextPropagator());

const createProvider = () => {
  // Detect AWS Lambda resources synchronously
  const awsResource = new AwsLambdaDetectorSync().detect();
  
  // Merge AWS resource with service name
  const resource = new Resource({
    [ATTR_SERVICE_NAME]: process.env.AWS_LAMBDA_FUNCTION_NAME || 'my-lambda-function',
  }).merge(awsResource);

  const provider = new NodeTracerProvider({ resource });

  // Configure the stdout exporter
  const exporter = new StdoutOTLPExporterNode({
    timeoutMillis: 5000,
    compression: 'gzip',  // No compression for Lambda stdout
  });

  // Use BatchSpanProcessor for efficient processing
  provider.addSpanProcessor(new BatchSpanProcessor(exporter));

  return provider;
};

// Initialize the provider
const provider = createProvider();
provider.register();
const tracer = trace.getTracer('lambda-function');

async function processEvent(event) {
  const span = tracer.startSpan('process_event');
  
  try {
    // Your processing logic here
    return { processed: true };
  } finally {
    span.end();
  }
}

// Example Lambda handler with tracing
exports.handler = async (event, context) => {
  const parentSpan = tracer.startSpan('lambda_handler', {
    kind: SpanKind.SERVER
  });

  return await context.with(trace.setSpan(context.active(), parentSpan), async () => {
    try {
      // Add event information to span
      parentSpan.setAttribute('event.type', event.type);
      parentSpan.addEvent('Processing Lambda event');

      // Your Lambda logic here
      const result = await processEvent(event);

      return {
        statusCode: 200,
        body: JSON.stringify(result)
      };
    } catch (error) {
      parentSpan.recordException(error);
      parentSpan.setStatus({ code: 1 });
      throw error;
    } finally {
      parentSpan.end();
      // Ensure spans are exported before Lambda freezes
      await provider.forceFlush();
    }
  });
};

Lambda Configuration Notes and Best Practices

  • The exporter writes to stdout, which is automatically captured by CloudWatch Logs
  • Always call provider.forceFlush() before the Lambda handler completes if you want to ensure all spans are exported when using a batch span processor
  • The AwsLambdaDetectorSync automatically detects Lambda environment details
  • Consider Lambda timeout when setting timeoutMillis for the exporter

It may be advisable to set the protocol to http/protobuf and enable compression to reduce the overhead (and cost)of JSON serialization in a serverless environment, by setting the environment variables:

OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_COMPRESSION=gzip

Best Practices

  1. Initialize Outside Handler

    • Create the provider and tracer outside the handler to reuse across invocations
  2. Resource Detection

    • Use AwsLambdaDetectorSync to automatically capture Lambda metadata
    • Merge with custom resources as needed
  3. Span Processing

    • Use BatchSpanProcessor for efficient span processing
    • Always flush spans before handler completion
  4. Error Handling

    • Record exceptions and set appropriate span status
    • Ensure spans are ended in finally blocks
  5. Context Propagation

    • Use W3C Trace Context for distributed tracing
    • Propagate context in outgoing requests

Configuration

Environment Variables

| Variable | Description | Default | |----------|-------------|---------| | OTEL_EXPORTER_OTLP_PROTOCOL | Protocol to use ('http/json' or 'http/protobuf') | 'http/protobuf' | | OTEL_EXPORTER_OTLP_ENDPOINT | General endpoint URL | http://localhost:4318 | | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | Traces-specific endpoint URL | - | | OTEL_SERVICE_NAME | Service name | - | | AWS_LAMBDA_FUNCTION_NAME | Fallback service name | - | | OTEL_EXPORTER_OTLP_COMPRESSION | Compression algorithm ('gzip' or 'none') | 'none' |

Output Format

The exporter writes JSON objects to stdout in the following format:

{
  "__otel_otlp_stdout": "@dev7a/[email protected]",
  "source": "service-name",
  "endpoint": "endpoint-url",
  "method": "POST",
  "content-type": "application/json",
  "headers": {},
  "payload": "...",
  "base64": true,
  "content-encoding": "gzip"
}

The __otel_otlp_stdout field is used to identify the data as telemetry data from this exporter, and is used to define a CloudWatch Logs subscription filter for the Lambda OTLP Forwarder.

License

MIT