How to Set Up Structured Logging with Dewy: Complete Configuration Guide
To set up structured logging with Dewy, invoke the SetupLogger function with your desired log level and format, then pass the resulting *logging.Logger to the Dewy constructor or CLI components.
Dewy leverages Go’s standard log/slog package to deliver high-performance structured logging throughout its deployment automation workflow. Whether you’re operating Dewy as a standalone CLI tool or embedding it as a library in your own Go application, configuring the logger requires understanding its two-layer architecture and CLI flag integration.
Architecture of Dewy’s Logging System
Dewy implements structured logging through a thin wrapper around log/slog, allowing you to toggle between JSON and text output formats while maintaining consistent leveled logging (DEBUG, INFO, WARN, ERROR).
The Core Logger Type
In logging/logger.go, the Logger struct embeds a standard *slog.Logger and tracks the output format:
type Logger struct {
*slog.Logger // embeds slog.Logger for structured logging
format string // "json" or "text"
}
The Format() method (lines 10–19) returns the stored format string, enabling downstream components to inspect whether the output mode is JSON or text. This design allows Dewy to maintain type safety while exposing the full slog API for structured key-value pairs.
SetupLogger Implementation Details
The SetupLogger function in logging/logger.go (lines 21–59) constructs the logger through a four-step process:
- Level Parsing: Converts string levels (DEBUG, INFO, WARN, ERROR) to
slog.Levelconstants using a case-insensitive switch onstrings.ToUpper(level). - Output Handling: Defaults to
os.Stderrwhen the providedio.Writeris nil. - Handler Selection: Uses
strings.ToLower(format)to choose betweenslog.NewJSONHandler(for"json") andslog.NewTextHandler(for any other value, including"text"). - Wrapper Construction: Returns a
*Loggerembedding the configuredslog.Logger.
func SetupLogger(level, format string, output io.Writer) *Logger {
// Parse level, select handler, and return wrapped logger
}
Public API Wrapper
Dewy exposes this functionality through a public wrapper in dewy/logger.go (lines 8–11):
func SetupLogger(level, format string, output io.Writer) *logging.Logger {
return logging.SetupLogger(level, format, output)
}
This indirection allows the github.com/linyows/dewy package to maintain a stable public API while the internal logging package handles implementation details.
Configuring Structured Logging via CLI
When running Dewy as a command-line tool, structured logging is controlled through global flags defined in cli.go.
Available Flags
| Setting | CLI Flag | Default Value | Options |
|---|---|---|---|
| Log level | --log-level or -l |
ERROR |
DEBUG, INFO, WARN, ERROR |
| Log format | --log-format or -f |
text |
json, text |
CLI Usage Example
To run Dewy with verbose JSON logging for debugging deployment issues:
dewy --log-level DEBUG --log-format json \
--registry docker://registry.example.com/myapp:latest \
--notifier slack://hooks.slack.com/services/TOKEN
The CLI initialization code in cli.go (lines 75–78) parses these flags and constructs the logger:
// Set up structured logger
slogger := SetupLogger(c.LogLevel, c.LogFormat, c.env.Err)
d, err := New(conf, slogger)
The slogger instance propagates to all subsystems including registry clients, container runtimes, and notification handlers.
Programmatic Configuration
For Go developers embedding Dewy as a library, you can instantiate loggers directly without CLI flags.
Basic Library Setup
Import the logging package and create a configured instance:
package main
import (
"os"
"github.com/linyows/dewy/logging"
)
func main() {
// Create JSON logger at INFO level writing to stdout
logger := logging.SetupLogger("INFO", "json", os.Stdout)
// Emit structured log entry
logger.Info("deployment initiated",
"application", "api-service",
"version", "v2.1.0",
"target", "production",
)
}
This outputs a machine-parseable JSON line:
{"time":"2024-01-15T09:30:00Z","level":"INFO","msg":"deployment initiated","application":"api-service","version":"v2.1.0","target":"production"}
Using the Dewy Wrapper
Alternatively, use the public wrapper for consistency with CLI-based setups:
import "github.com/linyows/dewy"
func main() {
logger := dewy.SetupLogger("WARN", "text", os.Stderr)
// This appears as text: level=WARN msg="configuration loaded" path=/etc/dewy.conf
logger.Warn("configuration loaded", "path", "/etc/dewy.conf")
}
Runtime Format Inspection
You can conditionally handle output based on the logger’s format using the Format() accessor:
if logger.Format() == "json" {
// Apply JSON-specific middleware or parsing
} else {
// Handle human-readable text output
}
Integration with Dewy Components
Once instantiated, the logger integrates seamlessly with Dewy’s core engine. The New function in the main package accepts *logging.Logger as its second parameter, passing it to:
- Registry clients (Docker, GitHub Releases, etc.) for pull operation logging
- Notifiers (Slack, Webhook) for delivery status reporting
- Container runtimes for deployment event streams
All components that accept *logging.Logger utilize the embedded slog.Logger methods (Debug(), Info(), Warn(), Error()) with structured key-value pairs for observability.
Summary
- Core Implementation: Dewy’s structured logging lives in
logging/logger.go, wrapping Go’slog/slogwith format-aware configuration. - Configuration Method: Use
SetupLogger(level, format, output)specifying DEBUG/INFO/WARN/ERROR levels and json/text formats. - CLI Integration: Pass
--log-leveland--log-formatflags to the Dewy binary; the CLI injects the configured logger into the main service incli.go. - Programmatic Use: Import
github.com/linyows/dewy/loggingor usedewy.SetupLoggerto create loggers for embedding Dewy in Go applications. - Output Inspection: Call
logger.Format()to determine if the output handler is JSON or text for conditional processing.
Frequently Asked Questions
What log levels does Dewy support for structured logging?
Dewy supports four standard levels: DEBUG, INFO, WARN, and ERROR. These map directly to Go’s slog.Level constants. The level string is case-insensitive during configuration, so "debug", "DEBUG", and "Debug" are equivalent.
Can I redirect Dewy’s structured logs to a file instead of stderr?
Yes. The SetupLogger function accepts any io.Writer, not just os.Stderr. Pass an os.File handle or bytes.Buffer as the third argument to capture logs to files, memory buffers, or custom writers for testing and log aggregation.
How do I switch between human-readable and machine-parseable output?
Specify "text" for human-readable key=value pairs (suitable for terminal viewing) or "json" for structured JSON lines (optimal for log aggregation systems like ELK or Datadog). This is controlled via the --log-format CLI flag or the second parameter to SetupLogger.
Is it possible to change the log level after Dewy has started?
No. The current implementation in logging/logger.go creates the slog.Handler with a fixed level during SetupLogger initialization. To change levels, you must restart the Dewy process or recreate the *logging.Logger instance with a different level parameter.
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 →