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 intime.DateTimeformatprofile– Deployment profile (e.g.,prod,dev)color– Optional UI color tagcaller– File and line number of the log callsvc– Service namesver– Service versionnode– Node nametrace– Kratos trace IDspan– 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.Initinxlog/log.go:22-43with 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, andspanas defined inxlog/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →