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/backendStart 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/otelginConfigure 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).
| Option | Description | Default |
|---|---|---|
WithPort(port) | HTTP port for the Traceway server | 8082 |
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 startup | None |
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).