Hone logo
Hone
Problems

Structured Logging in Go

Modern applications generate a significant amount of data. Effectively managing and analyzing this data is crucial for debugging, monitoring, and understanding application behavior. Structured logging, which formats log messages with key-value pairs, makes logs machine-readable and significantly easier to query and process compared to traditional plain text logs. This challenge will guide you in implementing a basic structured logging system in Go.

Problem Description

Your task is to create a Go package that provides structured logging capabilities. This package should allow users to log messages at different severity levels (e.g., INFO, WARN, ERROR) and include arbitrary key-value pairs as context for each log entry. The output should be in a standardized, machine-readable format.

Key Requirements:

  • Log Levels: Support at least INFO, WARN, and ERROR log levels.
  • Structured Output: Log entries should be formatted as JSON.
  • Contextual Data: Allow adding custom key-value pairs to each log entry.
  • Timestamp: Each log entry must include a timestamp.
  • Message: Each log entry must include a message.
  • Error Handling: The logging mechanism itself should be robust and not panic on invalid input.

Expected Behavior:

When a log function is called (e.g., LogInfo, LogWarn, LogError), it should output a JSON string to standard output. This JSON object will contain fields like level, message, timestamp, and any additional key-value pairs provided.

Edge Cases:

  • Logging with no additional context.
  • Logging with various data types for context values (strings, integers, booleans, etc.).
  • Handling potential errors during JSON marshaling (though in this simplified scenario, it's unlikely with standard Go types).

Examples

Example 1:

// Assuming you have a logger instance named 'logger'
logger.Info("User logged in", "userID", 123, "username", "alice")
{"level":"INFO","message":"User logged in","timestamp":"2023-10-27T10:00:00Z","userID":123,"username":"alice"}

Explanation: An INFO level log message with two additional key-value pairs: userID and username. The timestamp will be the current time when the log is generated.

Example 2:

// Assuming you have a logger instance named 'logger'
logger.Error("Database connection failed", "error", "timeout", "host", "localhost")
{"level":"ERROR","message":"Database connection failed","timestamp":"2023-10-27T10:01:00Z","error":"timeout","host":"localhost"}

Explanation: An ERROR level log message with context about the failure.

Example 3:

// Assuming you have a logger instance named 'logger'
logger.Warn("Low disk space detected")
{"level":"WARN","message":"Low disk space detected","timestamp":"2023-10-27T10:02:00Z"}

Explanation: A WARN level log message with only a message and no additional context.

Constraints

  • The logging package should be self-contained within a single Go file.
  • The output format must be strictly JSON.
  • All log entries must be written to os.Stdout.
  • The timestamp format should be RFC3339.
  • The context key-value pairs will be provided as variadic arguments (e.g., key1, value1, key2, value2, ...). It's assumed that these pairs are always valid (i.e., an even number of arguments, where keys are strings and values can be any serializable type).

Notes

  • Consider using the encoding/json package for marshaling log entries.
  • The time package will be useful for generating timestamps.
  • A common approach is to define a struct that represents a log entry and then marshal that struct to JSON.
  • The variadic nature of context arguments (...interface{}) can be handled by iterating through them in pairs.
  • For simplicity, you don't need to implement log rotation, different output destinations, or advanced filtering. The focus is on the structured output itself.
Loading editor...
go