Skip to main content

Logging & Monitoring

OPS Intermediate

Configure logging and monitoring for EZ-Console.

Overview

EZ-Console provides comprehensive logging and monitoring capabilities. Logs can be configured for different levels, formats, and outputs. Monitoring can be integrated with Prometheus, Grafana, and other observability tools.

Logging Configuration

Basic Logging

log:
level: "info" # debug, info, warn, error
format: "json" # json, logfmt
path: "logs" # Log directory

Log Levels

  • debug: Detailed information for debugging
  • info: General informational messages
  • warn: Warning messages
  • error: Error messages

Log Formats

  • json: JSON format (default, recommended for production)
  • logfmt: Logfmt format (human-readable)

Configuration Options

log:
level: "info" # Log level
format: "json" # Log format
path: "logs" # Log directory
output: "stdout" # Output: stdout, file, both
file: "app.log" # Log file name (when output=file)
max_size: 100 # Max file size in MB
max_backups: 10 # Number of backup files
max_age: 30 # Max age in days
compress: true # Compress old log files

Command-Line Configuration

./server \
--log.level=debug \
--log.format=json \
--log.path=logs

Environment Variables

export LOG_LEVEL=info
export LOG_FORMAT=json
export LOG_PATH=logs

Log Output

Console Output

log:
output: "stdout"
format: "logfmt" # Human-readable for console

File Output

log:
output: "file"
path: "logs"
file: "app.log"
max_size: 100
max_backups: 10
max_age: 30
compress: true

Both Console and File

log:
output: "both"
path: "logs"
format: "json"

Structured Logging

JSON Format Example

{
"level": "info",
"time": "2024-01-15T10:30:00Z",
"msg": "User logged in",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"username": "john.doe",
"ip": "192.168.1.100"
}

Using in Code

import (
"github.com/sven-victor/ez-console/pkg/util"
)

func (c *ProductController) CreateProduct(ctx *gin.Context) {
util.Logger.Info("Creating product",
"user_id", userID,
"product_name", req.Name,
)

// ...
}

Log Rotation

Log files are automatically rotated when they reach the maximum size:

log:
max_size: 100 # Rotate at 100MB
max_backups: 10 # Keep 10 backup files
max_age: 30 # Delete logs older than 30 days
compress: true # Compress old log files

Monitoring

Health Check Endpoint

GET /api/health

Response:

{
"code": "0",
"data": {
"status": "ok",
"timestamp": "2024-01-15T10:30:00Z"
}
}

Metrics Endpoint

EZ-Console can expose Prometheus metrics:

import "github.com/prometheus/client_golang/prometheus/promhttp"

router.GET("/metrics", gin.WrapH(promhttp.Handler()))

Prometheus Integration

  1. Expose Metrics:
router.GET("/metrics", gin.WrapH(promhttp.Handler()))
  1. Configure Prometheus:
# prometheus.yml
scrape_configs:
- job_name: 'ez-console'
static_configs:
- targets: ['localhost:8080']

Grafana Dashboard

Create Grafana dashboards to visualize:

  • Request rates
  • Response times
  • Error rates
  • Database query performance
  • System resources

Tracing

EZ-Console supports distributed tracing through OpenTelemetry, allowing you to track requests across services. Configure tracing exporters to send trace data to various backends.

Configuration Structure

tracing:
service_name: "ez-console" # Service name for trace identification
http: # HTTP exporter for OpenTelemetry Collector
grpc: # gRPC exporter for OpenTelemetry Collector
zipkin: # Zipkin exporter
file: # File exporter (for local debugging)

Common Options

  • service_name: Service identifier in traces (required)

OpenTelemetry HTTP Integration

Send traces via HTTP to OpenTelemetry Collector or compatible backends:

tracing:
service_name: "ez-console"
http:
endpoint: "localhost:4317" # Collector endpoint (host:port)
url_path: "/v1/traces" # URL path for traces endpoint
timeout: 30s # Request timeout
insecure: true # Skip TLS verification (dev only)
compression: "gzip" # Compression: true/false/1/0/"gzip" (gzip) or false/0/"false" (none)
retry:
enabled: true # Enable retry (default: true)
initial_interval: 5s # Initial retry interval (default: 5s)
max_interval: 30s # Maximum retry interval (default: 30s)
max_elapsed_time: 1m # Maximum total retry time (default: 1m)
header: # Custom HTTP headers
Authorization: "Bearer token123"
tls_config: # TLS configuration
cert_file: "/path/to/cert.pem"
key_file: "/path/to/key.pem"
ca_file: "/path/to/ca.pem"
server_name: "collector.example.com"
insecure_skip_verify: false

Configuration Options:

  • endpoint: Collector endpoint address (host:port)
  • url_path: HTTP path for traces (default: /v1/traces)
  • timeout: Request timeout duration
  • insecure: Skip TLS certificate verification (use only in development)
  • compression: Compression setting
    • true, "true", 1, "1", "gzip" → gzip compression
    • false, "false", 0, "0" → no compression (default: no compression)
  • retry: Retry configuration for failed requests (default: enabled)
    • enabled: Enable/disable retry (can be set to false string to disable)
    • initial_interval: Initial retry interval (default: 5s)
    • max_interval: Maximum retry interval (default: 30s)
    • max_elapsed_time: Maximum total time for all retries (default: 1m)
  • header: Custom HTTP headers (e.g., authentication tokens)
  • tls_config: TLS configuration for secure connections
    • cert_file: Client certificate file path
    • key_file: Client private key file path
    • ca_file: CA certificate file path
    • server_name: Server name for certificate validation
    • insecure_skip_verify: Skip TLS verification

OpenTelemetry gRPC Integration

Send traces via gRPC to OpenTelemetry Collector (recommended for production):

tracing:
service_name: "ez-console"
grpc:
endpoint: "localhost:4318" # Collector gRPC endpoint (host:port)
timeout: 30s # Request timeout
insecure: false # Skip TLS verification (dev only)
compression: "gzip" # Compression: true/false/1/0/"gzip" (gzip) or false/0/"false" (none)
reconnection_period: 5s # Reconnection interval for failures
retry:
enabled: true # Enable retry (default: true)
initial_interval: 5s # Initial retry interval (default: 5s)
max_interval: 30s # Maximum retry interval (default: 30s)
max_elapsed_time: 1m # Maximum total retry time (default: 1m)
header: # Custom gRPC metadata
api-key: "secret-key"
tls_config: # TLS configuration
cert_file: "/path/to/cert.pem"
key_file: "/path/to/key.pem"
ca_file: "/path/to/ca.pem"
server_name: "collector.example.com"
insecure_skip_verify: false
service_config: "" # gRPC service config JSON string

Configuration Options:

  • endpoint: Collector gRPC endpoint address (host:port)
  • timeout: Request timeout duration
  • insecure: Skip TLS certificate verification (use only in development)
  • compression: Compression setting
    • true, "true", 1, "1", "gzip" → gzip compression
    • false, "false", 0, "0" → no compression (default: no compression)
  • reconnection_period: Duration to wait before reconnecting after connection loss
  • retry: Retry configuration for failed requests (same structure as HTTP retry)
  • header: Custom gRPC metadata headers
  • tls_config: TLS configuration (same structure as HTTP)
  • service_config: Optional gRPC service configuration JSON

gRPC vs HTTP:

  • gRPC: Lower latency, better performance, recommended for production
  • HTTP: Easier firewall configuration, works with HTTP load balancers

Zipkin Integration

Send traces directly to Zipkin backend:

tracing:
service_name: "ez-console"
zipkin:
endpoint: "http://localhost:9411/api/v2/spans" # Zipkin API endpoint

Configuration Options:

  • endpoint: Full URL to Zipkin spans API endpoint (typically /api/v2/spans)

File Integration

Export traces to local file for debugging and testing:

tracing:
service_name: "ez-console"
file:
path: "traces.json" # Output file path

Configuration Options:

  • path: File path where traces will be written (JSON format)

Use Cases:

  • Local development and debugging
  • Offline trace collection
  • Testing trace generation without collector

Example Configurations

Development (HTTP, insecure):

tracing:
service_name: "ez-console"
http:
endpoint: "localhost:4317"
insecure: true
compression: false # Disable compression (or use "false", 0)

Production (gRPC, secure):

tracing:
service_name: "ez-console"
grpc:
endpoint: "collector.example.com:4318"
insecure: false
compression: "gzip"
timeout: 30s
tls_config:
ca_file: "/etc/ssl/ca.pem"
server_name: "collector.example.com"

Local Debugging (File):

tracing:
service_name: "ez-console"
file:
path: "./traces.json"

Log Aggregation

ELK Stack

Send logs to Elasticsearch:

log:
output: "file"
format: "json"
path: "logs"

Then use Filebeat to ship to Elasticsearch.

Loki

Send logs to Grafana Loki:

log:
output: "stdout"
format: "json"

Use Promtail to collect and send to Loki.

Alerting

Prometheus Alerts

# alerts.yml
groups:
- name: ez-console
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
for: 5m
annotations:
summary: "High error rate detected"

Log-Based Alerts

Monitor logs for critical errors:

# Use log monitoring tools
tail -f logs/app.log | grep ERROR

Best Practices

1. Use Structured Logging

// ✅ Good: Structured logging
util.Logger.Info("User created",
"user_id", userID,
"username", username,
)

// ❌ Bad: String formatting
util.Logger.Info(fmt.Sprintf("User %s created", username))

2. Appropriate Log Levels

  • debug: Development and troubleshooting
  • info: Normal operations
  • warn: Recoverable issues
  • error: Errors requiring attention

3. Don't Log Sensitive Data

// ❌ Bad: Log passwords
util.Logger.Info("User login", "password", password)

// ✅ Good: Log user ID only
util.Logger.Info("User login", "user_id", userID)

4. Centralized Logging

Use log aggregation tools (ELK, Loki) for centralized logging in production.

Troubleshooting

Logs Not Appearing

Solutions:

  1. Check log level setting
  2. Verify log path permissions
  3. Check disk space
  4. Verify output configuration

High Log Volume

Solutions:

  1. Increase log level (info → warn)
  2. Enable log rotation
  3. Use log sampling
  4. Filter unnecessary logs

Need help? Ask in GitHub Discussions.