vercelreceiver

package module
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 27, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

README

Vercel Drains Receiver

OpenTelemetry Collector receiver for receiving observability data from Vercel Drains.

Overview

This receiver accepts logs, traces, speed insights, and web analytics data from Vercel's drain system via HTTP endpoints. It supports signature verification for security and multiple data formats.

Supported Data Types

  • Logs: Runtime, build, and static logs from Vercel deployments
  • Traces: Distributed tracing data using OpenTelemetry Protocol (OTLP)
  • Speed Insights: Performance metrics and web vitals
  • Web Analytics: Page views and custom events

Building a Custom Collector Distribution

To include this receiver in your own custom OpenTelemetry Collector distribution using the OpenTelemetry Collector Builder (OCB), follow these steps:

Prerequisites
  1. Install OCB:

    go install go.opentelemetry.io/collector/cmd/builder@latest
    
  2. Ensure you have Go 1.24+ installed

Creating a Builder Configuration

Create a YAML configuration file (e.g., builder-config.yaml) that includes the Vercel receiver:

dist:
  name: otelcol-custom
  description: Custom OpenTelemetry Collector with Vercel Receiver
  output_path: ./dist
  otelcol_version: v0.138.0  # Match your collector version

receivers:
  # Include the Vercel receiver from the published module
  - gomod: github.com/control-theory/vercelreceiver v0.1.0
  
  # Add other receivers as needed
  # - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.138.0
  # - gomod: go.opentelemetry.io/collector/receiver/prometheusreceiver v0.138.0

processors:
  # Add any processors you need
  # - gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.138.0

exporters:
  # Add exporters you need
  # - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.138.0
  # - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.138.0
Building the Collector

Once you have your builder configuration:

  1. Build the custom collector:

    builder --config=builder-config.yaml
    
  2. The built binary will be located at:

    ./dist/otelcol-custom
    
  3. Test your custom collector:

    ./dist/otelcol-custom --version
    
Version Compatibility

Make sure to use a compatible version of the receiver that matches your OpenTelemetry Collector version. The receiver should be compatible with collector versions v0.138.0 and later. Check the releases page for available versions.

For more information about OCB, see the OpenTelemetry Collector Builder documentation.

Configuration

Basic Configuration

The receiver uses a single HTTP server for all data types:

receivers:
  vercel:
    endpoint: "0.0.0.0:8080"  # Single endpoint for all drain types
    secret: "your-secret-key"  # Default secret for all endpoints
Advanced Configuration

You can customize routes and secrets per signal type:

receivers:
  vercel:
    endpoint: "0.0.0.0:8080"
    secret: "default-secret-key"  # Default secret for all endpoints

    # Optional per-signal overrides
    logs:
      route: "/custom-logs"      # Override default /logs route
      secret: "logs-secret"       # Override default secret for logs only

    traces:
      route: "/custom-traces"     # Override default /traces route

    speed_insights:
      secret: "metrics-secret"    # Override secret only (keeps default /speed-insights route)

    web_analytics:
      # Uses defaults: route=/analytics, secret from top-level
Configuration Fields
Top-Level Fields
  • endpoint (optional): Host and port to listen on. Default: :8080
  • secret (optional): Default secret for x-vercel-signature header verification. If not provided, signature verification is disabled for all endpoints unless overridden per signal.
Per-Signal Fields (logs, traces, speed_insights, web_analytics)

Each signal type supports optional overrides:

  • route (optional): Custom HTTP route for this signal type. If not provided, defaults are:
    • Logs: /logs
    • Traces: /traces
    • Speed Insights: /speed-insights
    • Web Analytics: /analytics
  • secret (optional): Secret specific to this signal type. Overrides the top-level secret if provided.

Endpoints

The receiver exposes the following HTTP endpoints:

  • POST /logs - Receives log drain data
  • POST /traces - Receives trace drain data
  • POST /speed-insights - Receives speed insights data
  • POST /analytics - Receives web analytics data
  • GET /health - Health check endpoint

Vercel Configuration

Configure your Vercel drains to send data to these endpoints:

Logs Drain
Endpoint URL: https://your-collector-domain.com/logs
Format: JSON or NDJSON
Secret: your-secret-key (optional)
Traces Drain
Endpoint URL: https://your-collector-domain.com/traces
Format: JSON or Protobuf
Secret: your-secret-key (optional)
Speed Insights Drain
Endpoint URL: https://your-collector-domain.com/speed-insights
Format: JSON or NDJSON
Secret: your-secret-key (optional)
Web Analytics Drain
Endpoint URL: https://your-collector-domain.com/analytics
Format: JSON or NDJSON
Secret: your-secret-key (optional)

Signature Verification

The receiver supports Vercel's signature verification using the x-vercel-signature header. The signature is computed using HMAC-SHA256:

secret := []byte("your-secret-key")
mac := hmac.New(sha256.New, secret)
mac.Write(bodyBytes)
signature := hex.EncodeToString(mac.Sum(nil))

If no secret is configured, signature verification is skipped.

Data Formats

Logs

Supports both JSON array and NDJSON (newline-delimited JSON) formats.

JSON Array Format:

[
  {
    "id": "1573817187330377061717300000",
    "deploymentId": "dpl_233NRGRjVZX1caZrXWtz5g1TAksD",
    "source": "build",
    "host": "my-app-abc123.vercel.app",
    "timestamp": 1573817187330,
    "level": "info",
    "message": "Build completed successfully"
  }
]

NDJSON Format:

{"id": "1573817187330377061717300000","deploymentId": "dpl_233NRGRjVZX1caZrXWtz5g1TAksD","source": "build","host": "my-app-abc123.vercel.app","timestamp": 1573817187330,"level": "info","message": "Build completed successfully"}
Traces

Supports JSON and Protobuf formats following the OpenTelemetry Protocol (OTLP) specification.

JSON Format:

{
  "resourceSpans": [{
    "resource": {
      "attributes": [{
        "key": "vercel.projectId",
        "value": {"stringValue": "Qmc52npNy86S8VV4Mt8a8dP1LEkRNbgosW3pBCQytkcgf2"}
      }]
    },
    "scopeSpans": [{
      "scope": {"name": "vercel"},
      "spans": [{
        "traceId": "7bba9f33312b3dbb8b2c2c62bb7abe2d",
        "spanId": "086e83747d0e381e",
        "name": "GET /api/users",
        "kind": "server"
      }]
    }]
  }]
}
Speed Insights

Converts web vitals (CLS, LCP, FID, FCP, TTFB, INP) to OpenTelemetry metrics.

Web Analytics

Converts pageviews and custom events to OpenTelemetry logs with event attributes.

Testing

Test Logs Endpoint
curl -X POST http://localhost:8080/logs \
  -H "Content-Type: application/json" \
  -H "x-vercel-signature: your-signature" \
  -d '[
    {
      "id": "test123",
      "deploymentId": "dpl_test",
      "source": "build",
      "host": "test.vercel.app",
      "timestamp": 1573817187330,
      "level": "info",
      "message": "Test log message",
      "projectId": "proj_test"
    }
  ]'
Test Traces Endpoint
curl -X POST http://localhost:8080/traces \
  -H "Content-Type: application/json" \
  -H "x-vercel-signature: your-signature" \
  -d '{
    "resourceSpans": [{
      "resource": {"attributes": []},
      "scopeSpans": [{
        "scope": {"name": "test"},
        "spans": [{
          "traceId": "7bba9f33312b3dbb8b2c2c62bb7abe2d",
          "spanId": "086e83747d0e381e",
          "name": "test_span"
        }]
      }]
    }]
  }'
Test Speed Insights Endpoint
curl -X POST http://localhost:8080/speed-insights \
  -H "Content-Type: application/json" \
  -H "x-vercel-signature: your-signature" \
  -d '[{
    "schema": "vercel.speed_insights.v1",
    "timestamp": "2023-09-14T15:30:00.000Z",
    "metricType": "LCP",
    "value": 2.5
  }]'

Architecture

The receiver uses a unified architecture:

  • Single HTTP Server: Manages all endpoints on one port (default :8080)
  • Shared Receiver: One receiver instance handles all signal types (logs, traces, metrics, analytics)
  • Authentication: Signature verification with default secret and per-signal overrides
  • Flexible Routing: Configurable routes per signal type with sensible defaults
  • Schema Conversion: Converts Vercel data formats to OpenTelemetry data models

Example Configurations

Minimal Setup (No Authentication)
receivers:
  vercel:
    # Uses all defaults: endpoint :8080, no authentication, default routes
Simple Setup (One Secret for All)
receivers:
  vercel:
    endpoint: "0.0.0.0:8080"
    secret: "my-shared-secret"
Per-Environment Secrets
receivers:
  vercel:
    endpoint: "0.0.0.0:8080"
    secret: "default-secret"

    logs:
      secret: "logs-only-secret"

    traces:
      secret: "traces-only-secret"
Custom Routes with Authentication
receivers:
  vercel:
    endpoint: "0.0.0.0:8080"
    secret: "shared-secret"

    logs:
      route: "/v1/logs"

    traces:
      route: "/v1/traces"
      secret: "traces-specific-secret"

    speed_insights:
      route: "/v1/metrics"

    web_analytics:
      route: "/v1/analytics"

License

This receiver is part of the Lawrence project.

Documentation

Overview

Package vercelreceiver implements an OpenTelemetry Collector receiver for Vercel Drains.

The Vercel receiver accepts observability data from Vercel's drain system via HTTP endpoints. It supports logs, traces (OTLP), speed insights (metrics), and web analytics data.

Configuration

The receiver uses a unified configuration with a single HTTP endpoint for all data types. By default, it listens on port 8080 and exposes the following routes:

  • POST /logs - Receives log drain data
  • POST /traces - Receives trace drain data (OTLP JSON or Protobuf)
  • POST /speed-insights - Receives speed insights/web vitals data
  • POST /analytics - Receives web analytics events
  • GET /health - Health check endpoint

Basic configuration example:

receivers:
  vercel:
    endpoint: "0.0.0.0:8080"
    secret: "your-secret-key"

Advanced configuration with per-signal overrides:

receivers:
  vercel:
    endpoint: "0.0.0.0:8080"
    secret: "default-secret"
    logs:
      route: "/custom-logs"
      secret: "logs-specific-secret"
    traces:
      route: "/custom-traces"
    speed_insights:
      secret: "metrics-secret"
    web_analytics:
      # Uses defaults

Authentication

The receiver supports Vercel's signature verification using the x-vercel-signature header. Signatures are computed using HMAC-SHA256. Authentication can be configured globally or per signal type. If no secret is configured, signature verification is disabled.

Data Formats

The receiver accepts multiple data formats:

  • Logs: JSON array or NDJSON (newline-delimited JSON)
  • Traces: OTLP JSON or OTLP Protobuf
  • Speed Insights: JSON array or NDJSON
  • Web Analytics: JSON array or NDJSON

All data is converted to OpenTelemetry's internal data model (pdata) before being passed to the configured consumers.

Index

Constants

View Source
const (
	TypeStr = "vercel"
)

Variables

View Source
var (
	LogsStability    = component.StabilityLevelBeta
	TracesStability  = component.StabilityLevelBeta
	MetricsStability = component.StabilityLevelBeta
)

Functions

func NewFactory

func NewFactory() receiver.Factory

Types

type Config

type Config struct {
	// Single endpoint for all data types (host:port format)
	Endpoint string `mapstructure:"endpoint"`

	// Default secret for all endpoints (can be overridden per signal type)
	Secret string `mapstructure:"secret"`

	// Default signature algorithm for all endpoints (can be overridden per signal type)
	SignatureAlgorithm string `mapstructure:"signature_algorithm"`

	// Per-signal configuration (optional overrides for routes and secrets)
	Logs          SignalConfig `mapstructure:"logs"`
	Traces        SignalConfig `mapstructure:"traces"`
	SpeedInsights SignalConfig `mapstructure:"speed_insights"`
	WebAnalytics  SignalConfig `mapstructure:"web_analytics"`
}

func (*Config) GetLogsSecret

func (cfg *Config) GetLogsSecret() string

GetLogsSecret returns the secret for logs (per-signal override or default)

func (*Config) GetSignatureAlgorithm

func (cfg *Config) GetSignatureAlgorithm() string

GetSignatureAlgorithm returns the signature algorithm (global for all signals)

func (*Config) GetSpeedInsightsSecret

func (cfg *Config) GetSpeedInsightsSecret() string

GetSpeedInsightsSecret returns the secret for speed insights (per-signal override or default)

func (*Config) GetTracesSecret

func (cfg *Config) GetTracesSecret() string

GetTracesSecret returns the secret for traces (per-signal override or default)

func (*Config) GetWebAnalyticsSecret

func (cfg *Config) GetWebAnalyticsSecret() string

GetWebAnalyticsSecret returns the secret for web analytics (per-signal override or default)

func (*Config) Validate

func (cfg *Config) Validate() error

Validate validates the configuration

type SharedComponent

type SharedComponent struct {
	component.Component
	// contains filtered or unexported fields
}

SharedComponent ensures that the wrapped component is started and stopped only once. When stopped it is removed from the SharedComponents map.

func (*SharedComponent) Shutdown

func (r *SharedComponent) Shutdown(ctx context.Context) error

Shutdown implements component.Component.

func (*SharedComponent) Start

func (r *SharedComponent) Start(ctx context.Context, host component.Host) error

Start implements component.Component.

func (*SharedComponent) Unwrap

func (r *SharedComponent) Unwrap() component.Component

Unwrap returns the original component.

type SharedComponents

type SharedComponents struct {
	// contains filtered or unexported fields
}

SharedComponents a map that keeps reference of all created instances for a given configuration, and ensures that the shared state is started and stopped only once.

func NewSharedComponents

func NewSharedComponents() *SharedComponents

NewSharedComponents returns a new empty SharedComponents.

func (*SharedComponents) GetOrAdd

func (scs *SharedComponents) GetOrAdd(key any, create func() component.Component) *SharedComponent

GetOrAdd returns the already created instance if exists, otherwise creates a new instance and adds it to the map of references.

type SignalConfig

type SignalConfig struct {
	Route  string `mapstructure:"route"`  // Optional: Override default route
	Secret string `mapstructure:"secret"` // Optional: Override default secret
}

SignalConfig defines configuration for a specific signal type (logs, traces, metrics, analytics) Both route and secret are optional and will use defaults if not provided

type SignatureAlgorithm

type SignatureAlgorithm string

SignatureAlgorithm defines the supported signature algorithms

const (
	SignatureAlgorithmSHA1   SignatureAlgorithm = "sha1"
	SignatureAlgorithmSHA256 SignatureAlgorithm = "sha256"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL