winston-loki

repository·development·Indexed 41 days ago

https://github.com/janianttonen/winston-loki

A Winston transport for Grafana Loki (version 6.1.4) that allows sending logs directly to Loki. It supports log batching, custom labels, and integration with Grafana Cloud Loki via basic authentication. Key features include configurable batching intervals, JSON or Protobuf transport, and the ability to convert Winston metadata into Loki labels.

Tokens
1.8K
Snippets
4
Records
6
Agent score
1%

What's inside winston-loki

  1. How to use winston-loki as a Winston transport

    development

    To use winston-loki, integrate it as a transport within a Winston logger instance. You must provide a host URL pointing to your Grafana Loki instance. For most simple setups, setting json: true and providing the correct host is sufficient.

    To include custom labels for specific log entries, pass a labels object within the log metadata.

    const { createLogger, transports } = require("winston");
    const LokiTransport = require("winston-loki");
    
    const logger = createLogger({
      transports: [
        new LokiTransport({
          host: "http://127.0.0.1:3100"
        })
      ]
    });
    
    // Using custom labels per log entry
    logger.debug({ message: 'test', labels: { 'key': 'value' } });
  2. Configure LokiTransport options

    development

    The LokiTransport constructor accepts a configuration object.

    Required Parameter:

    • host: The URL for your Grafana Loki instance (e.g., http://127.0.0.1:3100).

    Other Available Options:

    ParameterDescriptionDefault
    intervalInterval in seconds at which batched logs are sent5
    jsonUse JSON instead of Protobuf for transportfalse
    batchingIf false, logs are sent immediately as they arrivetrue
    clearOnErrorDiscard logs that result in an error during transportfalse
    replaceTimestampReplace log timestamps with Date.now(). Recommended to keep true to avoid upload failures due to upstream Loki changes.true
    labelsCustom key-value pairs applied to all logsundefined
    formatA Winston format (e.g., winston.format.json())undefined
    gracefulShutdownWait for unsent batches before exitingtrue
    timeoutRequest timeout for Grafana Loki in msundefined
    basicAuthCredentials in username:password formatundefined
    onConnectionErrorCallback function for Loki connection errorsundefined
    useWinstonMetaAsLabelsUse Winston's "meta" (like defaultMeta) as Loki labelsfalse
    ignoredMetaList of meta keys to ignore when useWinstonMetaAsLabels is enabledundefined
  3. Configure LokiTransport for Grafana Cloud Loki

    development

    When using Grafana Cloud Loki, you must provide the LOKI_HOST, a USER_ID, and a GRAFANA_CLOUD_TOKEN (created via Cloud Access Policies with logs:write scope). The authentication is passed via the basicAuth option in the format USER_ID:GRAFANA_CLOUD_TOKEN.

    const { createLogger, transports } = require("winston");
    const LokiTransport = require("winston-loki");
    
    const options = {
      transports: [
        new LokiTransport({
            host: 'LOKI_HOST', // e.g., https://logs-prod-006.grafana.net
            labels: { app: 'my-app' },
            json: true,
            basicAuth: 'USER_ID:GRAFANA_CLOUD_TOKEN', // e.g., '372040:your_token_here'
            format: winston.format.json(),
            replaceTimestamp: true,
            onConnectionError: (err) => console.error(err),
        })
      ]
    };
    
    const logger = createLogger(options);
    logger.debug({ message: 'test', labels: { 'key': 'value' } });
  4. Configure LokiTransport labels and metadata

    development

    You can control how Loki labels are generated using the following options in the LokiTransport constructor:

    • labels: An object of static labels to include in every log entry.
    • useWinstonMetaAsLabels: If true, all metadata attached to the Winston log (excluding ignoredMeta) will be converted into Loki labels.
    • ignoredMeta: An array of strings representing keys in the Winston metadata that should not be converted into Loki labels.
    • labels (within the log object): If the info object passed to Winston contains a labels key, these will be merged into the final Loki labels.

    Label Precedence & Logic:

    1. The level is always included as a label.
    2. If useWinstonMetaAsLabels is true: Metadata (minus ignoredMeta) is merged into labels.
    3. Else if labels (config) is provided: Static config labels are merged.
    4. Else: A job label is created using the label property from the log info.
    5. Finally, any labels property found directly on the log info object are merged in last.
  5. Use LokiTransport to integrate Winston with Grafana Loki

    development

    The LokiTransport class is a Winston transport designed to send logs to Grafana Loki. It handles log formatting, label management, and batching to optimize network requests.

    When a log is processed, the transport determines labels based on your configuration (either using static labels, Winston metadata, or a job label) and formats the log line. It then pushes the log entry into an internal batcher for efficient transmission.

    Key lifecycle methods:

    • log(info, callback): Overwrites the standard Winston transport method to process and batch logs.
    • flush(): Returns a promise that resolves once all currently batched logs have been successfully sent to Loki.
    • close(): Initiates a graceful shutdown by flushing remaining logs and closing the batcher connection.
    const winston = require('winston');
    const LokiTransport = require('winston-loki');
    
    const logger = winston.createLogger({
      transports: [
        new LokiTransport({
          host: 'http://localhost:3100',
          // ... other options
        })
      ]
    });
  6. Flush or close LokiTransport for graceful shutdown

    development

    Because LokiTransport uses an internal batcher to group logs, logs might not be sent immediately. To ensure no logs are lost during application shutdown, you must explicitly flush or close the transport.

    • Use await transport.flush() to wait for all currently queued logs to be sent.
    • Use await transport.close() during process termination to flush remaining logs and shut down the batcher cleanly. It is recommended to await the promise returned by close() to prevent the process from exiting before the final HTTP request completes.
    const transport = new LokiTransport({
      host: 'http://localhost:3100'
    });
    
    // ... application logic ...
    
    // On shutdown
    process.on('SIGTERM', async () => {
      await transport.close();
      process.exit(0);
    });