Tracepanel

Tracing your code

Add steps of your own to a trace with Span, run a task linked to its request with Go, make a job a trace with Command, name the signed-in user with SetUser, and print values to look at with Dump.

Tracepanel records requests, SQL, logs and calls on its own. To see your own code in a trace, wrap it in tracepanel.Span. To trace work that isn't a request, use tracepanel.Go for a task and tracepanel.Command for a job. To look at values while you work, print them with tracepanel.Dump.

Span

Span starts a step of the trace in the context, until you call the function it returns. The SQL, calls and logs made with the context it returns go inside the step in the call tree:

ctx, end := tracepanel.Span(ctx, "render invoice")
defer end()

Outside a trace, Span returns the context as it is.

Go

Go runs a function on a goroutine of its own, as a task. The task is a trace of its own, which the console lists under Tasks. The request that started it shows the start as a step, and the task links back to it:

tracepanel.Go(ctx, "send welcome email", func(ctx context.Context) error {
	return mailer.Send(ctx, user)
})

The task's context keeps the request's values, but isn't canceled when the request ends. An error the function returns, or a panic, fails the task.

Command

Command runs a function as a trace of its own, such as a scheduled job, a command or a migration. The console lists it under Jobs:

err := tracepanel.Command(ctx, "nightly report", func(ctx context.Context) error {
	return report.Build(ctx, db)
})

It returns what the function returns. An error or a panic fails the trace, and the panic goes on.

Programs without a server

A worker or a command-line tool has no handler to wrap. Call tracepanel.Setup first, and tracepanel.Flush before the program exits, so its traces reach the agent:

func main() {
	tracepanel.Setup(tracepanel.Config{Service: "shop-worker"})
	defer tracepanel.Flush(time.Second)

	_ = tracepanel.Command(context.Background(), "import feed", importFeed)
}

SetUser

SetUser names the signed-in user on the trace in the context. Call it where the app knows who is signed in, such as its auth middleware:

tracepanel.SetUser(r.Context(), strconv.FormatInt(user.ID, 10), user.Email)

The trace gets user.id, and user.username when the username isn't empty. The console shows whose request it was, and finds a user's traces. The username stays on your machine. Outside a trace, SetUser does nothing.

Dump

Dump is a debug print. It prints each value with the expression that gave it, as Go syntax, its type and its length, under the line that called it, on stderr:

tracepanel.Dump(ctx, order, user.Roles)
handlers.go:42 checkout
    order: &main.Order{
        ID:    7,
        Items: []main.Item{},
    } (*main.Order)
    user.Roles: []string{"admin"} ([]string) len=1

When the context carries a trace, the dump is recorded too, on the span it ran in, and the call tree always shows it, as a DUMP row. See Dumps. It prints in every build, recorded or not. A value whose expression names a secret, such as password, token or apiKey, is masked, and so is a value inside one under such a name: a struct's field, such as Password or APIKey, or a map's key, such as "session_id". It is masked printed and recorded alike. A name is read word by word, as for a request: authToken is masked, Author isn't. A value is cut at 16 KB.

On this page