# How to Set Up Structured Logging with Dewy: Complete Configuration Guide

> Learn how to set up structured logging with Dewy. This guide covers logger configuration and integration with Dewy components for enhanced observability. Get started now.

- Repository: [Tomohisa Oda/dewy](https://github.com/linyows/dewy)
- Tags: how-to-guide
- Published: 2026-03-06

---

**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`](https://github.com/linyows/dewy/blob/main/logging/logger.go), the `Logger` struct embeds a standard `*slog.Logger` and tracks the output format:

```go
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`](https://github.com/linyows/dewy/blob/main/logging/logger.go) (lines 21–59) constructs the logger through a four-step process:

1. **Level Parsing**: Converts string levels (DEBUG, INFO, WARN, ERROR) to `slog.Level` constants using a case-insensitive switch on `strings.ToUpper(level)`.
2. **Output Handling**: Defaults to `os.Stderr` when the provided `io.Writer` is nil.
3. **Handler Selection**: Uses `strings.ToLower(format)` to choose between `slog.NewJSONHandler` (for `"json"`) and `slog.NewTextHandler` (for any other value, including `"text"`).
4. **Wrapper Construction**: Returns a `*Logger` embedding the configured `slog.Logger`.

```go
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`](https://github.com/linyows/dewy/blob/main/dewy/logger.go) (lines 8–11):

```go
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`](https://github.com/linyows/dewy/blob/main/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:

```bash
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`](https://github.com/linyows/dewy/blob/main/cli.go) (lines 75–78) parses these flags and constructs the logger:

```go
// 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:

```go
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:

```json
{"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:

```go
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:

```go
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`](https://github.com/linyows/dewy/blob/main/logging/logger.go), wrapping Go’s `log/slog` with format-aware configuration.
- **Configuration Method**: Use `SetupLogger(level, format, output)` specifying DEBUG/INFO/WARN/ERROR levels and json/text formats.
- **CLI Integration**: Pass `--log-level` and `--log-format` flags to the Dewy binary; the CLI injects the configured logger into the main service in [`cli.go`](https://github.com/linyows/dewy/blob/main/cli.go).
- **Programmatic Use**: Import `github.com/linyows/dewy/logging` or use `dewy.SetupLogger` to 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`](https://github.com/linyows/dewy/blob/main/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.