Skip to main content

Send OpenTelemetry data from WebAssembly in Go

OpenTelemetry from WebAssembly

Overview

Enables the extraction of traces/spans from Wasm modules executing in a Golang program/application and emits them to OpenTelemetry collectors.

Installation

Install the OpenTelemetry adapter from GitHub:

go get github.com/dylibso/observe-sdk/go/adapter/opentelemetry@latest

Example

A basic Go program that loads a Wasm module and executes it using the Wazero WebAssembly runtime.

package main

import (
"context"
"log"
"os"
"time"

"github.com/dylibso/observe-sdk/go/adapter/opentelemetry"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
)

func main() {
// create a context
ctx := context.Background()

// create a new OpenTelemetry adapter with config
conf := &opentelemetry.OTelConfig{
ServiceName: "golang",
EmitTracesInterval: time.Second * 1,
TraceBatchMax: 100,
Endpoint: "localhost:4317",
Protocol: opentelemetry.GRPC,
AllowInsecure: true, // for localhost in dev via http
}

adapter := opentelemetry.NewOTelAdapter(conf)

// start the Observe SDK adapter
defer adapter.StopWithContext(ctx, true)
adapter.Start(ctx)

// load some Wasm from disk
wasm, err := os.ReadFile(os.Args[1])
if err != nil {
log.Panicln(err)
}

// setup a new Wazero runtime with config
wacfg := wazero.NewRuntimeConfig().WithCustomSections(true)
rt := wazero.NewRuntimeWithConfig(ctx, wacfg)

// apply the Observe SDK adapter to the Wazero runtime
traceCtx, err := adapter.NewTraceCtx(ctx, rt, wasm, nil)
if err != nil {
log.Panicln(err)
}

wasi_snapshot_preview1.MustInstantiate(ctx, rt)

// create a new Wazero configuration
modconfig := wazero.NewModuleConfig().
WithStdin(os.Stdin).
WithStdout(os.Stdout).
WithStderr(os.Stderr).
WithArgs(os.Args[1:]...).
WithStartFunctions("_start")

// instantiate the Wasm module
mod, err := rt.InstantiateWithConfig(ctx, wasm, modconfig)
if err != nil {
log.Println("module instance error:", err)
return
}
defer mod.Close(ctx)

// associate some additional metadata with the trace
meta := map[string]string{
"http.url": "https://example.com/my-endpoint",
"http.status_code": "200",
"http.client_ip": "192.168.1.0",
}
traceCtx.Metadata(meta)

// stop the trace
traceCtx.Finish()
}

Adapter Configuration

You may modify the behavior of your adapter by passing in a configuration when initializing the adapter. A configuration has the following fields:

config := &OTelConfig{
// the URL of your OpenTelemetry collector
Endpoint: "localhost:4317",
// the dataset to group your observability data under
ServiceName: "golang",
// the protocol to use to emit telemetry data (either HTTP or GRPC)
Protocol: opentelemetry.GRPC,
// if running in a development environment without TLS
AllowInsecure: true,
// how often to send traces
EmitTracesInterval: time.Second * 1,
// the maximum number of traces to send per request
TraceBatchMax: 100,
}

adapter := NewOTelAdapter(config)