Metadata Context
Metadata context allows you to attach key-value pairs to log entries, providing essential information for debugging and understanding log events. This is the primary mechanism for adding structured data to your logs.
Context Basics
Use WithContext() to attach metadata to individual log entries:
Go
import "github.com/bytehide/bytehide-logs-go"
// Single context value
logs.WithContext("userId", "user_123").
Info("User logged in")
// Multiple context values
logs.WithContext("userId", "user_123").
WithContext("email", "john@example.com").
WithContext("ipAddress", "192.168.1.1").
Info("User authentication successful")
// Different data types
logs.WithContext("orderId", "ORD-456").
WithContext("amount", 99.99).
WithContext("itemCount", 3).
WithContext("paid", true).
Info("Order processed")import "github.com/bytehide/bytehide-logs-go"
// Single context value
logs.WithContext("userId", "user_123").
Info("User logged in")
// Multiple context values
logs.WithContext("userId", "user_123").
WithContext("email", "john@example.com").
WithContext("ipAddress", "192.168.1.1").
Info("User authentication successful")
// Different data types
logs.WithContext("orderId", "ORD-456").
WithContext("amount", 99.99).
WithContext("itemCount", 3).
WithContext("paid", true).
Info("Order processed")Global Metadata Context
Use AddMetaContext() to add metadata that persists across multiple log entries:
Go
import "github.com/bytehide/bytehide-logs-go"
// Add once at request start
func init() {
logs.AddMetaContext("appVersion", "1.0.0")
logs.AddMetaContext("environment", "production")
logs.AddMetaContext("region", "us-east-1")
}
// Automatically included in all logs
logs.Info("User login")
// Logged with: {appVersion: 1.0.0, environment: production, region: us-east-1, message: User login}
logs.Debug("Cache hit")
// Logged with: {appVersion: 1.0.0, environment: production, region: us-east-1, message: Cache hit}import "github.com/bytehide/bytehide-logs-go"
// Add once at request start
func init() {
logs.AddMetaContext("appVersion", "1.0.0")
logs.AddMetaContext("environment", "production")
logs.AddMetaContext("region", "us-east-1")
}
// Automatically included in all logs
logs.Info("User login")
// Logged with: {appVersion: 1.0.0, environment: production, region: us-east-1, message: User login}
logs.Debug("Cache hit")
// Logged with: {appVersion: 1.0.0, environment: production, region: us-east-1, message: Cache hit}Practical Examples
HTTP Request Handling
Go
func (h *OrderHandler) HandleCreateOrder(w http.ResponseWriter, r *http.Request) {
// Log request details
logs.WithContext("method", r.Method).
WithContext("path", r.URL.Path).
WithContext("remoteAddr", r.RemoteAddr).
WithContext("userAgent", r.Header.Get("User-Agent")).
Debug("Incoming request")
// Parse request body
var req CreateOrderRequest
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
logs.WithContext("path", r.URL.Path).
WithContext("error", err.Error()).
Error("Failed to decode request", err)
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
// Log parsed request context
logs.WithContext("customerId", req.CustomerID).
WithContext("itemCount", len(req.Items)).
WithContext("total", req.Total).
Debug("Request parsed successfully")
// Process order
order, err := h.service.CreateOrder(&req)
if err != nil {
logs.WithContext("customerId", req.CustomerID).
WithContext("itemCount", len(req.Items)).
Error("Order creation failed", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
// Log response context
logs.WithContext("orderId", order.ID).
WithContext("customerId", req.CustomerID).
WithContext("total", order.Total).
WithContext("status", order.Status).
Info("Order created successfully")
// Return response
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(order)
}func (h *OrderHandler) HandleCreateOrder(w http.ResponseWriter, r *http.Request) {
// Log request details
logs.WithContext("method", r.Method).
WithContext("path", r.URL.Path).
WithContext("remoteAddr", r.RemoteAddr).
WithContext("userAgent", r.Header.Get("User-Agent")).
Debug("Incoming request")
// Parse request body
var req CreateOrderRequest
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
logs.WithContext("path", r.URL.Path).
WithContext("error", err.Error()).
Error("Failed to decode request", err)
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
// Log parsed request context
logs.WithContext("customerId", req.CustomerID).
WithContext("itemCount", len(req.Items)).
WithContext("total", req.Total).
Debug("Request parsed successfully")
// Process order
order, err := h.service.CreateOrder(&req)
if err != nil {
logs.WithContext("customerId", req.CustomerID).
WithContext("itemCount", len(req.Items)).
Error("Order creation failed", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
// Log response context
logs.WithContext("orderId", order.ID).
WithContext("customerId", req.CustomerID).
WithContext("total", order.Total).
WithContext("status", order.Status).
Info("Order created successfully")
// Return response
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(order)
}Database Operations
Go
func (r *OrderRepository) GetOrdersByCustomer(ctx context.Context, customerId string) ([]Order, error) {
logs.WithContext("customerId", customerId).
Trace("Querying orders by customer")
query := "SELECT id, customer_id, total, status, created_at FROM orders WHERE customer_id = $1 ORDER BY created_at DESC"
rows, err := r.db.QueryContext(ctx, query, customerId)
if err != nil {
logs.WithContext("customerId", customerId).
WithContext("query", "GetOrdersByCustomer").
Error("Query execution failed", err)
return nil, err
}
defer rows.Close()
var orders []Order
for rows.Next() {
var order Order
err := rows.Scan(&order.ID, &order.CustomerID, &order.Total, &order.Status, &order.CreatedAt)
if err != nil {
logs.WithContext("customerId", customerId).
Error("Failed to scan row", err)
return nil, err
}
orders = append(orders, order)
}
if err = rows.Err(); err != nil {
logs.WithContext("customerId", customerId).
Error("Row iteration failed", err)
return nil, err
}
logs.WithContext("customerId", customerId).
WithContext("orderCount", len(orders)).
Trace("Orders retrieved successfully")
return orders, nil
}func (r *OrderRepository) GetOrdersByCustomer(ctx context.Context, customerId string) ([]Order, error) {
logs.WithContext("customerId", customerId).
Trace("Querying orders by customer")
query := "SELECT id, customer_id, total, status, created_at FROM orders WHERE customer_id = $1 ORDER BY created_at DESC"
rows, err := r.db.QueryContext(ctx, query, customerId)
if err != nil {
logs.WithContext("customerId", customerId).
WithContext("query", "GetOrdersByCustomer").
Error("Query execution failed", err)
return nil, err
}
defer rows.Close()
var orders []Order
for rows.Next() {
var order Order
err := rows.Scan(&order.ID, &order.CustomerID, &order.Total, &order.Status, &order.CreatedAt)
if err != nil {
logs.WithContext("customerId", customerId).
Error("Failed to scan row", err)
return nil, err
}
orders = append(orders, order)
}
if err = rows.Err(); err != nil {
logs.WithContext("customerId", customerId).
Error("Row iteration failed", err)
return nil, err
}
logs.WithContext("customerId", customerId).
WithContext("orderCount", len(orders)).
Trace("Orders retrieved successfully")
return orders, nil
}Service Layer with Context
Go
type PaymentService struct {
gateway PaymentGateway
repo PaymentRepository
}
func (s *PaymentService) ProcessPayment(ctx context.Context, orderId string, amount float64) (string, error) {
logs.WithContext("orderId", orderId).
WithContext("amount", amount).
Debug("Processing payment")
// Validate amount
if amount <= 0 {
logs.WithContext("orderId", orderId).
WithContext("amount", amount).
Warn("Invalid payment amount")
return "", fmt.Errorf("invalid amount: %f", amount)
}
// Create charge request
start := time.Now()
transactionId, err := s.gateway.Charge(ctx, amount)
duration := time.Since(start)
if err != nil {
logs.WithContext("orderId", orderId).
WithContext("amount", amount).
WithContext("duration_ms", duration.Milliseconds()).
Error("Payment gateway request failed", err)
return "", err
}
logs.WithContext("orderId", orderId).
WithContext("amount", amount).
WithContext("transactionId", transactionId).
WithContext("duration_ms", duration.Milliseconds()).
Debug("Payment gateway charge succeeded")
// Save transaction
transaction := &Transaction{
ID: transactionId,
OrderID: orderId,
Amount: amount,
Status: "completed",
ProcessedAt: time.Now(),
}
err = s.repo.Save(transaction)
if err != nil {
logs.WithContext("orderId", orderId).
WithContext("transactionId", transactionId).
WithContext("amount", amount).
Error("Failed to save transaction", err)
return "", err
}
logs.WithContext("orderId", orderId).
WithContext("transactionId", transactionId).
WithContext("amount", amount).
Info("Payment processed and recorded successfully")
return transactionId, nil
}type PaymentService struct {
gateway PaymentGateway
repo PaymentRepository
}
func (s *PaymentService) ProcessPayment(ctx context.Context, orderId string, amount float64) (string, error) {
logs.WithContext("orderId", orderId).
WithContext("amount", amount).
Debug("Processing payment")
// Validate amount
if amount <= 0 {
logs.WithContext("orderId", orderId).
WithContext("amount", amount).
Warn("Invalid payment amount")
return "", fmt.Errorf("invalid amount: %f", amount)
}
// Create charge request
start := time.Now()
transactionId, err := s.gateway.Charge(ctx, amount)
duration := time.Since(start)
if err != nil {
logs.WithContext("orderId", orderId).
WithContext("amount", amount).
WithContext("duration_ms", duration.Milliseconds()).
Error("Payment gateway request failed", err)
return "", err
}
logs.WithContext("orderId", orderId).
WithContext("amount", amount).
WithContext("transactionId", transactionId).
WithContext("duration_ms", duration.Milliseconds()).
Debug("Payment gateway charge succeeded")
// Save transaction
transaction := &Transaction{
ID: transactionId,
OrderID: orderId,
Amount: amount,
Status: "completed",
ProcessedAt: time.Now(),
}
err = s.repo.Save(transaction)
if err != nil {
logs.WithContext("orderId", orderId).
WithContext("transactionId", transactionId).
WithContext("amount", amount).
Error("Failed to save transaction", err)
return "", err
}
logs.WithContext("orderId", orderId).
WithContext("transactionId", transactionId).
WithContext("amount", amount).
Info("Payment processed and recorded successfully")
return transactionId, nil
}Cache Operations
Go
type CacheService struct {
cache Cache
}
func (s *CacheService) GetOrFetch(ctx context.Context, key string, fetcher func() (interface{}, error)) (interface{}, error) {
logs.WithContext("key", key).
Trace("Checking cache")
// Try to get from cache
value, err := s.cache.Get(key)
if err == nil {
logs.WithContext("key", key).
WithContext("source", "cache").
Trace("Cache hit")
return value, nil
}
logs.WithContext("key", key).
WithContext("source", "fetch").
Debug("Cache miss, fetching value")
// Fetch fresh value
start := time.Now()
value, err = fetcher()
duration := time.Since(start)
if err != nil {
logs.WithContext("key", key).
WithContext("duration_ms", duration.Milliseconds()).
Error("Failed to fetch value", err)
return nil, err
}
logs.WithContext("key", key).
WithContext("duration_ms", duration.Milliseconds()).
Debug("Value fetched successfully")
// Store in cache
err = s.cache.Set(key, value, 24*time.Hour)
if err != nil {
logs.WithContext("key", key).
Warn("Failed to cache value")
// Don't return error - value was fetched successfully
}
logs.WithContext("key", key).
WithContext("ttlHours", 24).
Trace("Value cached")
return value, nil
}type CacheService struct {
cache Cache
}
func (s *CacheService) GetOrFetch(ctx context.Context, key string, fetcher func() (interface{}, error)) (interface{}, error) {
logs.WithContext("key", key).
Trace("Checking cache")
// Try to get from cache
value, err := s.cache.Get(key)
if err == nil {
logs.WithContext("key", key).
WithContext("source", "cache").
Trace("Cache hit")
return value, nil
}
logs.WithContext("key", key).
WithContext("source", "fetch").
Debug("Cache miss, fetching value")
// Fetch fresh value
start := time.Now()
value, err = fetcher()
duration := time.Since(start)
if err != nil {
logs.WithContext("key", key).
WithContext("duration_ms", duration.Milliseconds()).
Error("Failed to fetch value", err)
return nil, err
}
logs.WithContext("key", key).
WithContext("duration_ms", duration.Milliseconds()).
Debug("Value fetched successfully")
// Store in cache
err = s.cache.Set(key, value, 24*time.Hour)
if err != nil {
logs.WithContext("key", key).
Warn("Failed to cache value")
// Don't return error - value was fetched successfully
}
logs.WithContext("key", key).
WithContext("ttlHours", 24).
Trace("Value cached")
return value, nil
}Performance Monitoring
Go
type PerformanceMonitor struct {
threshold time.Duration
}
func (pm *PerformanceMonitor) MeasureOperation(name string, operation func() error) error {
start := time.Now()
logs.WithContext("operation", name).
Trace("Operation started")
err := operation()
duration := time.Since(start)
durationMs := duration.Milliseconds()
if err != nil {
logs.WithContext("operation", name).
WithContext("duration_ms", durationMs).
WithContext("status", "error").
Error("Operation failed", err)
return err
}
if duration > pm.threshold {
logs.WithContext("operation", name).
WithContext("duration_ms", durationMs).
WithContext("threshold_ms", pm.threshold.Milliseconds()).
WithContext("status", "slow").
Warn("Operation exceeded threshold")
} else {
logs.WithContext("operation", name).
WithContext("duration_ms", durationMs).
WithContext("status", "success").
Debug("Operation completed")
}
return nil
}type PerformanceMonitor struct {
threshold time.Duration
}
func (pm *PerformanceMonitor) MeasureOperation(name string, operation func() error) error {
start := time.Now()
logs.WithContext("operation", name).
Trace("Operation started")
err := operation()
duration := time.Since(start)
durationMs := duration.Milliseconds()
if err != nil {
logs.WithContext("operation", name).
WithContext("duration_ms", durationMs).
WithContext("status", "error").
Error("Operation failed", err)
return err
}
if duration > pm.threshold {
logs.WithContext("operation", name).
WithContext("duration_ms", durationMs).
WithContext("threshold_ms", pm.threshold.Milliseconds()).
WithContext("status", "slow").
Warn("Operation exceeded threshold")
} else {
logs.WithContext("operation", name).
WithContext("duration_ms", durationMs).
WithContext("status", "success").
Debug("Operation completed")
}
return nil
}Error Context with Recovery
Go
func (h *Handler) SafeExecute(operation func() error) error {
operationName := "unknown"
startTime := time.Now()
defer func() {
if r := recover(); r != nil {
duration := time.Since(startTime)
logs.WithContext("operation", operationName).
WithContext("duration_ms", duration.Milliseconds()).
WithContext("panic", fmt.Sprintf("%v", r)).
Critical("Panic occurred during operation")
}
}()
logs.WithContext("operation", operationName).
Trace("Executing operation")
err := operation()
if err != nil {
duration := time.Since(startTime)
logs.WithContext("operation", operationName).
WithContext("duration_ms", duration.Milliseconds()).
WithContext("error", err.Error()).
Error("Operation failed", err)
return err
}
duration := time.Since(startTime)
logs.WithContext("operation", operationName).
WithContext("duration_ms", duration.Milliseconds()).
WithContext("status", "success").
Debug("Operation completed successfully")
return nil
}func (h *Handler) SafeExecute(operation func() error) error {
operationName := "unknown"
startTime := time.Now()
defer func() {
if r := recover(); r != nil {
duration := time.Since(startTime)
logs.WithContext("operation", operationName).
WithContext("duration_ms", duration.Milliseconds()).
WithContext("panic", fmt.Sprintf("%v", r)).
Critical("Panic occurred during operation")
}
}()
logs.WithContext("operation", operationName).
Trace("Executing operation")
err := operation()
if err != nil {
duration := time.Since(startTime)
logs.WithContext("operation", operationName).
WithContext("duration_ms", duration.Milliseconds()).
WithContext("error", err.Error()).
Error("Operation failed", err)
return err
}
duration := time.Since(startTime)
logs.WithContext("operation", operationName).
WithContext("duration_ms", duration.Milliseconds()).
WithContext("status", "success").
Debug("Operation completed successfully")
return nil
}Context Value Types
ByteHide Logger supports various data types in context:
Go
// Strings
logs.WithContext("userId", "user_123").Info("msg")
// Numbers
logs.WithContext("count", 42).Info("msg")
logs.WithContext("amount", 99.99).Info("msg")
logs.WithContext("duration_ms", 1500).Info("msg")
// Booleans
logs.WithContext("success", true).Info("msg")
logs.WithContext("cached", false).Info("msg")
// Dates/Times
logs.WithContext("timestamp", time.Now()).Info("msg")
logs.WithContext("createdAt", createdTime).Info("msg")
// Collections (as strings)
logs.WithContext("tags", "[tag1,tag2,tag3]").Info("msg")
logs.WithContext("ids", "[1,2,3,4,5]").Info("msg")// Strings
logs.WithContext("userId", "user_123").Info("msg")
// Numbers
logs.WithContext("count", 42).Info("msg")
logs.WithContext("amount", 99.99).Info("msg")
logs.WithContext("duration_ms", 1500).Info("msg")
// Booleans
logs.WithContext("success", true).Info("msg")
logs.WithContext("cached", false).Info("msg")
// Dates/Times
logs.WithContext("timestamp", time.Now()).Info("msg")
logs.WithContext("createdAt", createdTime).Info("msg")
// Collections (as strings)
logs.WithContext("tags", "[tag1,tag2,tag3]").Info("msg")
logs.WithContext("ids", "[1,2,3,4,5]").Info("msg")Best Practices
Context Best Practices
- Use consistent key names - standardize across your codebase
- Include business context - orderId, userId, transactionId
- Include technical context - duration_ms, error, status
- Avoid sensitive data - use data masking for passwords, tokens
- Use meaningful values - provide context that aids debugging
- Limit context size - don't add excessive key-value pairs
- Use proper data types - numbers as numbers, booleans as booleans
Naming Conventions
Adopt consistent naming:
- IDs: userId, orderId, transactionId
- Durations: duration_ms, executionTime_ms
- Counts: itemCount, pageSize
- Status: status, statusCode, httpStatus
- References: customerId, productId, accountId