Event Fields

Send useful events.

Every event must include a message.

Everything else is optional, but adding the right fields makes searching, filtering, and creating alerts much easier.

Complete example

await log.error({
  message: "Stripe payment failed.",
  importance: "high",
  service: "billing",
  subsystem: "stripe",
  operation: "create-payment",
  track: {
    user_id: "user_123",
    custom: {
      payment_intent_id: "pi_123",
    },
  },
  security: {
    ip_address: "203.0.113.10",
  },
  metrics: {
    custom: {
      response_time_ms: 3200,
    },
  },
});

Core fields

FieldTypeRequiredPurpose
typeerror | warning | info | audit | metric | debug | successSet by methodThe kind of event. Logger methods set this for you.
messagestringYesHuman-readable explanation of what happened
importancelow | medium | high | criticalNoControls how serious the event is
servicestringNoThe part of your system that produced the event
subsystemstringNoA provider, module, or smaller component
operationstringNoThe action being performed
trackLogTrackNoBusiness and user-related context
securityLogSecurityNoSecurity-related context
metricsLogMetricsNoNumeric measurements and performance data
timestampsLogTimestampsNoEvent timing when you need to provide your own event time

message

Use a short sentence that someone can understand immediately.

message: "Stripe payment failed."

Good

message: "Database connection timed out"
message: "User signed in"
message: "Invoice generation failed"

Avoid vague messages

message: "Something went wrong"
message: "Error"
message: "Failed"

importance

Use importance to show how urgently an event needs attention.

importance: "critical"
ValueUse it for
lowMinor events that usually need no action
mediumUnexpected events worth reviewing
highImportant failures that may affect users
criticalSerious failures requiring immediate attention

Alerts can match this field, which makes it useful for production issues you care about immediately.

service

Use service to identify the main area of your application.

service: "billing"
authbillingcheckoutnotificationsworkerapi

subsystem

Use subsystem for a provider, library, or smaller component inside the service.

subsystem: "stripe"
stripepostgresredissendgridopenai

operation

Use operation to describe the action being performed.

operation: "create-payment"
sign-increate-paymentsend-emailprocess-ordergenerate-report

track

Use track for searchable business context.

track: {
  user_id: "user_123",
  role: "user",
  custom: {
    order_id: "order_456",
    payment_intent_id: "pi_789",
  },
}

This is the best place for identifiers that help you follow one user, request, order, or workflow.

Built-in track fields are user_id, role, ip, user_agent, and geo. Put product-specific identifiers inside custom.

Custom values can be strings, numbers, booleans, or null.

Privacy note

Avoid storing sensitive personal data unless your organization has approved it. Stable IDs are usually safer than raw emails or names.

security

Use security for security-related details.

security: {
  ip_address: "203.0.113.10",
  auth_status: "failed",
  suspicious: true,
  tags: ["checkout", "stripe"],
  custom: {
    reason: "payment-auth-failed",
  },
}

auth_status can be success, failed, or expired.

  • Failed login attempts
  • Suspicious requests
  • Permission failures
  • Blocked actions
  • Rate-limit events

metrics

Use metrics for numeric values.

metrics: {
  latency_ms: 3200,
  db_query_count: 3,
  custom: {
    response_time_ms: 3200,
    amount: 49.99,
  },
}

These values can help you understand performance and internal business behavior.

Built-in metric fields are latency_ms and db_query_count. Add your own numeric measurements inside custom.

Automatically added fields

You usually do not need to manually send these fields:

type

Set by logger methods such as log.info(), log.warn(), and log.error().

appName

Added from the logger configuration.

environment

Added from the logger configuration.

timestamps.event_time

Optional. Send this only when the event happened earlier than the moment you log it.

ingested_at

Internal receive time. You normally do not need to send this.

Recommended naming

Use lowercase, consistent values for top-level strings.

service: "billing"
subsystem: "stripe"
operation: "create-payment"

Avoid mixing styles.

service: "Billing"
service: "billing-service"
service: "BILLING"

Consistency makes filters and alerts reliable.

Inside track, security, metrics, and custom, use snake_case names.

track: {
  user_id: "user_123",
  custom: {
    payment_intent_id: "pi_123",
  },
}

Start simple

A beginner does not need every field.

await log.error({
  message: "Payment failed",
  service: "billing",
  importance: "high",
});

Add more context only when it helps you search, investigate, or alert.

Found something unexpected? Let us know.