Symbolicating JavaScript Stack Traces with the OpenTelemetry Collector


Translate JavaScript stack traces captured by the Honeycomb OpenTelemetry Web SDK into human-readable formats using Honeycomb’s Symbolicator Processor for the OpenTelemetry Collector.

Important
This feature is in beta.

What is the Symbolicator Processor? 

Honeycomb’s Symbolicator Processor makes JavaScript stack traces captured by the Honeycomb OpenTelemetry Web SDK easier to read by translating obfuscated or minified function names and addresses into human-readable formats (a process called symbolication) as they pass through your OpenTelemetry Collector.

Adding the Symbolicator Processor to your OpenTelemetry Collector automates this process, making debugging easier.

How It Works 

The Symbolicator Processor uses source maps to reconstruct the original source code from transformed stack traces. It supports:

  • Source Map Retrieval: Load source maps from local file systems, Amazon S3, and Google Cloud Storage (GCS).
  • Attribute Configuration: Customize attribute keys for stack trace elements, such as function names, line numbers, column numbers, and URLs.
  • Data Preservation: Retain both the original and symbolicated stack trace data for comparison or auditing.

Before You Begin 

Before you start, make sure:

  • You’re using the Honeycomb OpenTelemetry Web SDK v0.12.0 or later.

  • CGO is enabled. The processor relies on C libraries, so CGO must be enabled when building your OpenTelemetry Collector.

  • You’re using a compatible base image. If you’re using a custom-built OpenTelemetry Collector instance, it must support glibc.

    We recommend using gcr.io/distroless/cc, a lightweight container image that includes both CGO and glibc support, and is designed for security and minimalism.

Installation 

To install the Symbolicator Processor, add it to your OpenTelemetry distribution’s build configuration file:

processors:
  - gomod: github.com/honeycombio/opentelemetry-collector-symbolicator/symbolicatorprocessor v0.0.0
    name: symbolicatorprocessor
    path: ./symbolicatorprocessor

Alternatively, you can use the pre-built, custom Honeycomb OpenTelemetry Collector distro, which includes this processor by default.

Registering the Processor 

After installing the Symbolicator Processor, you must register it in your OpenTelemetry Collector configuration. To do this, add the processor to the processors section of your configuration file:

processors:
  symbolicator:

You can then configure the processor’s behavior by specifying settings, such as source map locations, file paths, and other options.

Tip
After updating the configuration file, restart the OpenTelemetry Collector to apply the changes.

Configuring Source Maps 

You can configure the processor to retrieve JavaScript source files and their corresponding source maps from one of the following storage locations:

  • Local file system: Loads source maps from a local file system.
  • AWS S3: Retrieves source maps from an S3 bucket.
  • Google Cloud Storage (GCS): Loads source maps from a GCS bucket.

Choose the appropriate storage method based on your infrastructure, ensuring that source maps are stored in a format the processor can recognize.

Tip
After updating the configuration file, restart the OpenTelemetry Collector to apply the changes.

Source Map File Requirements 

Before configuring a file store, make sure your JavaScript source files and source maps are correctly set up to support symbolication:

  • Provide both minimized Javascript files and source maps. The processor requires access to both your minimized JavaScript source files and their corresponding source maps, which are generated during your build process.

  • Use versioned file names with a hash. To prevent conflicts and ensure the correct file versions are used, include a hash in the file names of both source and source map files (for example, main.c383b093b0b66825a9c3.js).

  • Include sourceMappingURL in Javascript source files. Minimized JavaScript source files must contain a sourceMappingURL comment at the end, pointing to the relative path of the source map file. For example:

    //# sourceMappingURL=/static/dist/main.c383b093b0b66825a9c3.js.map
    
  • Ensure file paths align with stack trace locations. The processor extracts file paths from stack traces and uses them to locate the corresponding source maps. Verify that file paths in stack traces match the structure used in your configured file store.

Configuring a Local File Store 

By default, the processor loads source files from a local directory. Specify the file path in your OpenTelemetry Collector configuration:

processors:
  symbolicator:
    source_map_store: file_store  # Specify the file store to use (in this case, local disk)
    local_source_maps: # Configure loading source maps from local disk
      path: /tmp/sourcemaps # (optional) Set the base path for the files. Defaults to ".". 
Note

Verify that:

  • The OpenTelemetry Collector can access the specified directory.
  • File paths in stack traces match the structure used in your configured file store.

How the Processor Retrieves Files from Local Disk 

Each line of the stack trace includes the URL of the file it originated from. When retrieving source files from local disk, the processor:

  1. Extracts the file path from the stack trace. Example origin file URL: https://example.com/static/dist/main.c383b093b0b66825a9c3.js Extracted path: /static/dist/main.c383b093b0b66825a9c3.js.

  2. Prepends the configured path to the extracted path: Example path: /tmp/sourcemaps Final path: /tmp/sourcemaps/static/dist/main.c383b093b0b66825a9c3.js.map

  3. Uses the combined path to read the source map file from the local disk.

Configuring an AWS S3 Store 

Optionally, you can load source files from an AWS S3 bucket. Add to your OpenTelemetry Collector configuration:

processors:
  symbolicator:
    source_map_store: s3_store # Specify the file store to use (in this case, S3)
    s3_source_maps: # Configure loading source maps from S3
      bucket: source-maps-bucket # Specify the name of the bucket the files are stored in
      region: us-east-1 # (optional) Configure the geographical location of the bucket
      prefix: source-maps # (optional) Specify the key the files are stored under
Note

Verify that:

  • AWS credentials used by the OpenTelemetry Collector have permission to access the S3 bucket.
  • If using private S3 buckets, IAM roles or access keys are configured accordingly.
  • File paths in stack traces match the structure used in your configured file store.

How the Processor Retrieves Files from S3 

Each line of the stack trace includes the URL of the file it originated from. When retrieving source files from an S3 bucket, the processor:

  1. Extracts the file path from the stack trace. Example origin file URL: https://example.com/static/dist/main.c383b093b0b66825a9c3.js Extracted path: /static/dist/main.c383b093b0b66825a9c3.js.

  2. If you configure a prefix, prepends the prefix to the extracted path to create a key: Example prefix: source-maps Final S3 key: source-maps/static/dist/main.c383b093b0b66825a9c3.js.map

  3. Uses the key to retrieve the source map from the specified S3 bucket.

Configuring a Google Cloud Storage (GCS) Store 

Optionally, you can load source files from a Google Cloud Storage (GCS) bucket. Add to your OpenTelemetry Collector configuration:

    processors:
      symbolicator:
        source_map_store: gcs_store # Specify the file store to use (in this case, GCS)
        gcs_source_maps: # Configure loading source maps from GCS
          bucket: source-maps-bucket # Specify the name of the bucket the files are stored in
          prefix: source-maps # (optional) Specify the key the files are stored under
Note

Verify that:

  • The OpenTelemetry Collector has the necessary permissions to read from the bucket.
  • If using private buckets, authentication uses a service account with storage.objects.get access.
  • File paths in stack traces match the structure used in your configured file store.

How the Processor Retrieves Files from GCS 

Each line of the stack trace includes the URL of the file it originated from. When retrieving source files from a GCS bucket, the processor:

  1. Extracts the file path from the stack trace. Example origin file URL: https://example.com/static/dist/main.c383b093b0b66825a9c3.js Extracted path: /static/dist/main.c383b093b0b66825a9c3.js.

  2. If you configure a prefix, prepends the prefix to the extracted path to create a key: Example prefix: source-maps Final GCS key: source-maps/static/dist/main.c383b093b0b66825a9c3.js.map

  3. Uses the key to retrieve the source map from the specified GCS bucket.

Structuring Exception Data 

The Symbolicator Processor requires exception stack traces to be formatted into distinct attributes:

  • columns: Column numbers in the source file where the error occurred.
  • functions: Function names corresponding to each stack frame. If unknown, use "?".
  • lines: Line numbers in the source file where the error occurred.
  • urls: URLs of the JavaScript files referenced in the stack trace.

Each of these attributes must be an array (slice), and all four arrays must have the same length, with corresponding entries aligned across them. For example:

columns: [6465,3512358,3512661,3514018,758545]
functions: ["?","w.callback","push.Br+g.w.crossDomainError","XMLHttpRequest.<anonymous>","XMLHttpRequest.<anonymous>"]
lines: [3582,2,2,2,2]
urls: ["https://example.com/static/dist/main.c383b093b0b66825a9c3.js","https://example.com/static/dist/vendor.1c285a50f5307be9648d.js","https://example.com/static/dist/vendor.1c285a50f5307be9648d.js","https://example.com/static/dist/vendor.1c285a50f5307be9648d.js","https://example.com/static/dist/vendor.1c285a50f5307be9648d.js"]

Ensure proper formatting of stack trace data by checking for:

  • Consistent array lengths: Each attribute must contain the same number of elements.
  • Matching indices: The nth element in each array must correspond to the same stack frame.
  • Accurate URLs: The urls array must contain fully qualified URLs that match the structure used when retrieving source maps.

Advanced Configuration 

In addition to basic setup, you can customize how the Symbolicator Processor handles stack traces by configuring attribute mappings and additional processing options.

Tip
After updating the configuration file, restart the OpenTelemetry Collector to apply the changes.

Mapping Attributes 

Use these configuration options to specify which attributes the processor should read from and write to when handling stack traces:

Configuration Key Description Example Value
symbolicator_failure_attribute_key Indicates whether the symbolicator failed to fully process the stack trace. exception.symbolicator.failed
columns_attribute_key Attribute containing the column numbers of the source stack trace. exception.structured_stacktrace.columns
functions_attribute_key Attribute containing the function names for the source stack trace. exception.structured_stacktrace.functions
lines_attribute_key Attribute containing the line numbers of the source stack trace. exception.structured_stacktrace.lines
urls_attribute_key Attribute containing the script URLs associated with the source stack trace. exception.structured_stacktrace.urls
output_stack_trace_key Attribute where the symbolicated stack trace should be stored. exception.stacktrace
stack_type_key Attribute containing the exception type. exception.type
stack_message_key Attribute containing the exception message. exception.message
preserve_stack_trace Indicates whether to retain the original stack trace values as attributes after symbolication (true to preserve). true
original_stack_trace_key If preservation is enabled, key used to store the original stack trace. exception.stacktrace.original
original_columns_attribute_key If preservation is enabled, key used to store the original column numbers. exception.structured_stacktrace.functions.original
original_functions_attribute_key If preservation is enabled, key used to store the original function names. exception.structured_stacktrace.lines.original
original_lines_attribute_key If preservation is enabled, key used to store the original line numbers. exception.structured_stacktrace.columns.original
original_urls_attribute_key If preservation is enabled, key used to store the original script URLs. exception.structured_stacktrace.urls.original

Additional Processing Options 

Use these configuration options to control how stack traces are processed and managed:

Config Key Description Example Value
timeout Maximum time (in seconds) to wait for symbolication before timing out. 5
source_map_cache_size Maximum number of source maps to cache in memory. Reduce this value if the Collector encounters memory constraints. 128