Axiom Transport
Ships structured logs to Axiom using the official axiom-go SDK. The transport constructs a JSON object from each entry and sends it via Client.Ingest() as NDJSON.
Import path: go.loglayer.dev/transports/axiom/v3. Package name: axiom.
go get go.loglayer.dev/transports/axiom/v3Authenticating
Axiom authenticates with an API token. The transport takes a caller-supplied *axiom.Client (required; New panics with ErrClientRequired when it is nil). You construct the client yourself, and the axiom-go SDK reads the token from the environment for you:
| Env var | Read by | Purpose |
|---|---|---|
AXIOM_TOKEN | axiom-go SDK | API token with ingest permission. |
AXIOM_ORG_ID | axiom-go SDK | Organization ID (required for personal tokens). |
The dataset is set on the transport via Config.DatasetName, not an env var.
Using environment variables
import (
axiomgo "github.com/axiomhq/axiom-go/axiom"
"go.loglayer.dev/v3"
"go.loglayer.dev/transports/axiom/v3"
)
// The client picks up AXIOM_TOKEN (and AXIOM_ORG_ID for personal tokens)
// from the environment.
client, err := axiomgo.NewClient()
if err != nil {
panic(err)
}
log := loglayer.New(loglayer.Config{
Transport: axiom.New(axiom.Config{
Client: client,
DatasetName: "my-logs",
}),
})Basic Usage
import (
axiomgo "github.com/axiomhq/axiom-go/axiom"
"go.loglayer.dev/v3"
"go.loglayer.dev/transports/axiom/v3"
)
client, err := axiomgo.NewClient(
axiomgo.SetAPITokenConfig("your-api-token"),
)
if err != nil {
panic(err)
}
log := loglayer.New(loglayer.Config{
Transport: axiom.New(axiom.Config{
Client: client,
DatasetName: "my-logs",
}),
})
log.Info("user signed in")
log.WithMetadata(loglayer.Metadata{"userId": 42}).Warn("retry exhausted")Config
type Config struct {
transport.BaseConfig
Client *axiom.Client
DatasetName string
MessageField string
OnError func(error)
}| Field | Type | Default | Description |
|---|---|---|---|
Client | *axiom.Client | (required) | Constructed via axiom.NewClient() with authentication options. |
DatasetName | string | (required) | Axiom dataset ID or name to ingest logs into. |
MessageField | string | "msg" | The key under which the joined message text is placed in the JSON object. |
OnError | func(error) | stderr | Called when Client.Ingest() returns an error. |
Payload Shape
Each log entry is ingested as a JSON object:
msg: the joined message text (configurable viaMessageField)- Persistent fields from
WithFields(), merged at root - The serialized error from
WithError() - Metadata nested under the core's
MetadataFieldNamekey (default"metadata"; map metadata flattens at root only when the core runs withFlattenMetadata: true, the v2 shape)
log.WithFields(loglayer.Fields{"requestId": "abc"}).
WithError(errors.New("timeout")).
WithMetadata(loglayer.Metadata{"durationMs": 42}).
Info("served")results in:
{
"msg": "served",
"requestId": "abc",
"err": { "message": "timeout" },
"metadata": { "durationMs": 42 }
}Fatal Behavior
The transport never calls os.Exit or panic itself. The Axiom SDK is called synchronously per entry (Client.Ingest), so the fatal entry reaches Axiom before the log call returns. Whether the process terminates afterward is the LogLayer core's decision via Config.DisableFatalExit (default: exit). See Fatal Exits the Process.
Metadata Handling
Metadata follows the core placement rules: when Config.MetadataFieldName is empty, the core resolves it to "metadata" and the whole metadata value (map or non-map) nests under that key; with Config.FlattenMetadata: true (the v2 opt-out), map metadata merges at the root and non-map metadata nests under metadata.
Set Config.MetadataFieldName on the core to nest all metadata under a fixed key.
Level Mapping
LogLayer levels map directly to Axiom's expected level strings:
| LogLayer Level | Axiom Level |
|---|---|
LogLevelTrace | "trace" |
LogLevelDebug | "debug" |
LogLevelInfo | "info" |
LogLevelWarn | "warn" |
LogLevelError | "error" |
LogLevelFatal | "fatal" |
LogLevelPanic | "panic" |
GetLoggerInstance
Transport.GetLoggerInstance() returns the underlying *axiom.Client, useful for SDK features not exposed by the transport.
underlying := log.GetLoggerInstance(transportID).(*axiom.Client)