How to Set Up Structured Logging with xlog in Fabrica-Kit

Call xlog.Init("zap", "info", profile, color, svcName, svcVer, nodeName) early in your main.go to initialize a global JSON logger that automatically injects timestamps, service metadata, and distributed trace IDs into every log entry.

Setting up structured logging with xlog in fabrica-kit provides a production-ready observability foundation for Go microservices. The xlog package acts as a logging façade that integrates Kratos' logger abstraction with Uber's high-performance Zap encoder, outputting machine-readable JSON logs enriched with contextual fields like service name, version, and trace correlation IDs.

Core Architecture of xlog

The xlog package in [xlog/log.go](https://github.com/go-pantheon/fabrica-kit/blob/main/xlog/log.go) serves as the central configuration point. It wraps Kratos' log.Logger interface and, when the "zap" type is specified, configures a Zap JSON encoder that writes to stdout. This design ensures that once initialized, every log entry carries a consistent schema suitable for ingestion by ELK, Loki, or cloud-native logging platforms.

Configuring the Global Logger

The Init Function

The primary entry point is xlog.Init, defined in xlog/log.go:22-43. This function selects the concrete logger implementation and decorates it with permanent fields that appear in every subsequent log entry.

func Init(logType, logLevel, profile, color, name, version, nodeName string) log.Logger

Supported Log Types and Levels

As implemented in xlog/log.go:25-30, the system supports two logger types:

  • "zap" – Activates the Zap JSON encoder for structured output.
  • Any other value – Falls back to the default Kratos logger (plain text).

Log level handling occurs in xlog/log.go:60-71. The function accepts debug, info, warn, and error as valid strings, mapping them to Zap's native levels. Unrecognized levels default to Info to prevent startup failures.

Automatic Structured Fields

The initialization process injects a standard set of fields into every log entry, as defined in xlog/log.go:32-42:

  • ts – Timestamp in time.DateTime format
  • profile – Deployment profile (e.g., prod, dev)
  • color – Optional UI color tag
  • caller – File and line number of the log call
  • svc – Service name
  • sver – Service version
  • node – Node name
  • trace – Kratos trace ID
  • span – Kratos span ID

The Zap JSON encoder configuration in xlog/log.go:48-78 uses MsgKey = "msg" for the log message, lower-cases level names, formats time as ISO-8601, and writes output to stdout.

Implementation Examples

Basic Initialization in main.go

Call xlog.Init before any other logging operations to ensure the global logger is configured. This example demonstrates the typical bootstrap pattern:

package main

import (
	"log"

	"github.com/go-pantheon/fabrica-kit/xlog"
)

func main() {
	const (
		logType  = "zap"      // Use "zap" for JSON output
		logLevel = "info"     // debug | info | warn | error
		profile  = "prod"
		color    = "blue"
		svcName  = "order-service"
		svcVer   = "v1.2.3"
		nodeName = "node-01"
	)

	// Initialize the structured logger and register it globally
	logger := xlog.Init(logType, logLevel, profile, color, svcName, svcVer, nodeName)
	_ = logger

	// All subsequent log calls include structured fields automatically
	log.Info("service started")
}

Using the Logger in HTTP Handlers

After initialization, use the standard Kratos log package. The global logger automatically enriches entries with the fields configured during Init, including trace IDs from the request context:

package handler

import (
	"context"
	
	"github.com/go-kratos/kratos/v2/log"
)

func (h *Handler) GetUser(ctx context.Context, id string) (*User, error) {
	log.Infof("handling GetUser request", "userID", id)

	user, err := h.repo.Find(id)
	if err != nil {
		log.Errorf("failed to fetch user", "userID", id, "error", err)
		return nil, err
	}
	
	log.Debugf("user payload retrieved", "user", user)
	return user, nil
}

This produces JSON output similar to:

{
  "ts": "2026-03-02 15:04:05",
  "profile": "prod",
  "color": "blue",
  "caller": "handler/user.go:42",
  "svc": "order-service",
  "sver": "v1.2.3",
  "node": "node-01",
  "trace": "0a1b2c3d4e5f",
  "span": "6f7e8d9c0b1a",
  "level": "info",
  "msg": "handling GetUser request",
  "userID": "12345"
}

Component-Level Logger Overrides

For subsystems requiring additional context, create a child logger using log.With. Note that the underlying log level remains controlled by the global Init configuration:

subLogger := log.With(log.GetLogger(),
	"component", "payment",
	"region", "us-east-1",
)

subLogger.Infof("payment processor initialized")

Key Source Files

File Role Location
xlog/log.go Core implementation of Init, Zap encoder configuration, and field injection [xlog/log.go](https://github.com/go-pantheon/fabrica-kit/blob/main/xlog/log.go)
xcontext/context.go Request-scoped context utilities for trace propagation [xcontext/context.go](https://github.com/go-pantheon/fabrica-kit/blob/main/xcontext/context.go)
trace/trace.go Kratos tracing integration providing trace and span IDs to the logger [trace/trace.go](https://github.com/go-pantheon/fabrica-kit/blob/main/trace/trace.go)

Summary

  • xlog provides a structured logging façade in fabrica-kit that bridges Kratos and Zap for high-performance JSON output.
  • Initialize the logger via xlog.Init in xlog/log.go:22-43 with parameters for log type ("zap"), level (debug|info|warn|error), and service metadata.
  • Every log entry automatically includes fields for ts, profile, caller, svc, sver, node, trace, and span as defined in xlog/log.go:32-42.
  • The Zap encoder writes newline-delimited JSON to stdout, making logs immediately compatible with aggregation platforms like ELK, Loki, or cloud-native logging services.

Frequently Asked Questions

What log levels does xlog support?

The xlog.Init function accepts debug, info, warn, and error as valid level strings. As implemented in xlog/log.go:60-71, these are mapped to Zap's native levels. If an unrecognized string is provided, the system defaults to Info to prevent startup failures.

How do I switch from JSON to plain text logging?

Change the logType parameter in your xlog.Init call from "zap" to any other value. According to the logic in xlog/log.go:25-30, only the exact string "zap" triggers the JSON encoder; all other values fall back to the default Kratos logger, which produces human-readable plain text output.

Can I add custom fields to every log entry?

Yes, but you must do so at initialization or by creating child loggers. The xlog.Init function in xlog/log.go:32-42 hardcodes the standard fields like svc, sver, and node. For dynamic fields, use log.With(log.GetLogger(), "key", value) to create a contextual logger that carries additional key-value pairs for specific components or request scopes.

Where does xlog write its output?

By default, the Zap encoder configured in xlog/log.go:48-78 writes all output to stdout using a JSON encoder. The encoder uses ISO-8601 timestamps, lower-cased level names, and the message key "msg". This design ensures compatibility with modern log aggregation systems like ELK, Loki, or cloud-native logging services that expect newline-delimited JSON streams.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →