Thanks to visit codestin.com
Credit goes to docs.tracewayapp.com

Learn
Embedded Mode

Embedded Mode

Embedded mode runs a full Traceway server inside your Go process — using SQLite for all storage (relational data and telemetry). No Docker, no infrastructure — just one tracewaybackend.Run() call and your app has local observability.

This is intended for local development only. For production, use the Docker Compose or minimal deployment.

Want to see it in action? Check out the full working example on GitHub (opens in a new tab) — a complete Go app with embedded Traceway and OpenTelemetry instrumentation you can run in one command.

Quick Start

Install the Traceway backend module

go get github.com/tracewayapp/traceway/backend

Start Traceway inside your app

Call tracewaybackend.Run() in a goroutine during startup. It boots an in-memory SQLite server and seeds a default user and project:

package main
 
import (
	"github.com/gin-gonic/gin"
	tracewaybackend "github.com/tracewayapp/traceway/backend"
)
 
func main() {
	go tracewaybackend.Run(
		tracewaybackend.WithPort(8082),
		tracewaybackend.WithDefaultUser("[email protected]", "admin"),
		tracewaybackend.WithDefaultProject("My App", "go", "dev-token"),
	)
 
	router := gin.Default()
	// ... your routes
	router.Run(":8080")
}

Point OpenTelemetry to your local Traceway

Install the OTel dependencies:

go get go.opentelemetry.io/otel \
       go.opentelemetry.io/otel/sdk \
       go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp \
       go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin

Configure the OTLP exporter to send traces to the embedded server, and add the OTel middleware to your router:

package main
 
import (
	"context"
	"fmt"
	"time"
 
	"github.com/gin-gonic/gin"
	tracewaybackend "github.com/tracewayapp/traceway/backend"
	"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
)
 
const tracewayToken = "dev-token"
 
func main() {
	go tracewaybackend.Run(
		tracewaybackend.WithPort(8082),
		tracewaybackend.WithDefaultUser("[email protected]", "admin"),
		tracewaybackend.WithDefaultProject("My App", "go", tracewayToken),
	)
 
	shutdown := initTracer()
	defer shutdown()
 
	router := gin.Default()
	router.Use(otelgin.Middleware("my-app"))
 
	router.GET("/ping", func(c *gin.Context) {
		c.String(200, "pong")
	})
	router.Run(":8080")
}
 
func initTracer() func() {
	exporter, _ := otlptracehttp.New(
		context.Background(),
		otlptracehttp.WithEndpointURL("http://localhost:8082/api/otel/v1/traces"),
		otlptracehttp.WithHeaders(map[string]string{
			"Authorization": "Bearer " + tracewayToken,
		}),
	)
 
	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exporter),
		sdktrace.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceName("my-app"),
		)),
	)
	otel.SetTracerProvider(tp)
 
	return func() {
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()
		tp.Shutdown(ctx)
	}
}

The key parts:

  • Exporter URL points to http://localhost:8082/api/otel/v1/traces — the embedded server's OTLP endpoint
  • Authorization header uses the same token from WithDefaultProject

Open the dashboard

Run your app, then open http://localhost:8082 (opens in a new tab) in your browser.

Log in with the credentials from WithDefaultUser ([email protected] / admin).

Hit your app at http://localhost:8080/ping a few times — traces will appear in the Traceway dashboard within a few seconds.

Configuration Options

All options are passed to tracewaybackend.Run(). When any options are provided, embedded mode is activated automatically (pure SQLite).

OptionDescriptionDefault
WithPort(port)HTTP port for the Traceway server8082
WithServerURL(url)Base URL override (used in connection string output)http://localhost:{port}
WithSQLitePath(path)SQLite database file path:memory: (in-memory)
WithDefaultUser(email, password)Create a default admin user on startupNone
WithDefaultProject(name, framework, token)Create a default project with a fixed token (can be called multiple times)None

Multiple Projects

WithDefaultProject can be called multiple times to create separate projects — one for your Go backend, another for a frontend or any other service. Each project gets its own token, keeping telemetry organized in the dashboard:

go tracewaybackend.Run(
	tracewaybackend.WithPort(8082),
	tracewaybackend.WithDefaultUser("[email protected]", "admin"),
	tracewaybackend.WithDefaultProject("Backend", "go", "backend-token"),
	tracewaybackend.WithDefaultProject("Frontend", "sveltekit", "frontend-token"),
)

Data Persistence

By default, the database is in-memory — all data is lost when your application restarts. This is fine for quick debugging sessions, but if you want data to survive restarts, set a file path:

tracewaybackend.Run(
	tracewaybackend.WithSQLitePath("./traceway.db"),
	tracewaybackend.WithDefaultUser("[email protected]", "admin"),
	tracewaybackend.WithDefaultProject("My App", "go", "dev-token"),
)

WithSQLitePath stores everything — users, projects, traces, issues, and metrics — in a single SQLite file.

Seeding is idempotent — if the user from WithDefaultUser already exists, it's skipped.

Development-Only Guard

A common pattern is guarding embedded mode behind an environment check so it only runs in development:

if os.Getenv("ENV") != "production" {
	go tracewaybackend.Run(
		tracewaybackend.WithPort(8082),
		tracewaybackend.WithDefaultUser("[email protected]", "admin"),
		tracewaybackend.WithDefaultProject("My App", "go", "dev-token"),
	)
}

Full Example

For a complete working example with error recording and child spans, see the embedded-backend-otel example on GitHub (opens in a new tab).