title: Logging toc: false
In Go projects we use Logrus as our logging tool. We use the provided Logrus logging levels wrapped in a function defined in our api models, each with a custom response type initiated by its constructor function.
Response types should at least contain the following:
httpStatusCode int
applicationStatusCode string
entityStatusCode EntityStatusLevels
Trace: Extremely low-level, noisy details.
// Using API wrappers api.LogTrace(logger, api.CreateTrace( api.HttpStatusOK, api.ApplicationStatusSuccess, api.NotificationTracingFailed, // example entity status api.Metadata{TraceId: traceID, Function: "cacheProbe", Data: map[string]any{"key": "abc123"}}, ), nil)Debug: Developer-focused state inspection.
api.LogDebug(logger, api.CreateDebug( api.HttpStatusOK, api.ApplicationStatusSuccess, api.NotificationTracingFailed, api.Metadata{UserId: user.ID, Function: "authFlow", Data: map[string]any{"scopes": user.Scopes}}, ), nil)Info: Normal operational events.
api.LogInfo(logger, api.CreateSuccess( api.HttpStatusOK, api.ApplicationStatusGetSuccess, api.NotificationTracingFailed, api.Metadata{Function: "thumbnailJob", Data: map[string]any{"file": "video_1733992211.mp4"}}, ), map[string]any{"job": "thumbnailer"})Warn: Non-fatal anomalies worth attention.
api.LogWarning(logger, api.CreateWarning( api.HttpStatusServiceUnavailable, api.ApplicationStatusGetFailed, api.NotificationTracingFailed, api.Metadata{Function: "publish", Data: map[string]any{"retry_in_ms": 500}}, ), nil)Error: Failures that didn’t crash the process.
api.LogError(logger, api.CreateError( api.HttpStatusInternalServerError, api.ApplicationStatusError, api.NotificationTracingFailed, api.Metadata{DeviceId: device.ID, Error: err.Error(), Function: "mediaTransfer"}, ))Fatal: Critical error leading to process exit (calls os.Exit(1)).
api.LogFatal(logger, api.CreateFatal( api.HttpStatusServiceUnavailable, api.ApplicationStatusError, api.NotificationTracingFailed, api.Metadata{Function: "startup", Error: "missing DB URI"}, ), nil)Panic: Unexpected invariant violation (calls panic() after logging).
api.LogPanic(logger, api.CreatePanic( api.HttpStatusInternalServerError, api.ApplicationStatusError, api.NotificationTracingFailed, api.Metadata{Function: "streamRead", Error: "negative bytes read"}, ), nil)
Usage
For example:
func LogError(logger *logrus.Logger, errorResponse ErrorResponse) {
logger.WithFields(CreateErrorLog(logger, errorResponse)).Error()
}Can be used as:
api.LogError(logger, api.CreateError(
api.HttpStatusServiceUnavailable,
api.ApplicationStatusError,
api.NotificationTracingFailed,
api.Metadata{},
))Logger initialization example:
import (
"github.com/sirupsen/logrus"
)
logrus.SetFormatter(&logrus.JSONFormatter{})
logrus.SetOutput(os.Stdout)
logrus.SetLevel(logrus.InfoLevel)
// Set log level
logLevel := os.Getenv("LOG_LEVEL")
switch logLevel {
case "error":
logrus.SetLevel(logrus.ErrorLevel)
case "debug":
logrus.SetLevel(logrus.DebugLevel)
default:
logrus.SetLevel(logrus.InfoLevel)
}
// Initialize logger
logger := logrus.New()