/

Tags

Tags enable you to categorize and organize logs, making them easier to search, filter, and analyze. Use tags to identify log sources, types, and severity without cluttering log messages.

Tags Overview

Tags are string labels attached to log entries that help identify their source and purpose:

Go
import "github.com/bytehide/bytehide-logs-go"

// Add single tag
logs.WithTags("auth").Info("User login attempt")

// Add multiple tags
logs.WithTags("api", "request", "incoming").
    Info("Processing API request")

// Tags with context
logs.WithTags("database", "slow_query").
    WithContext("duration_ms", 5000).
    Warn("Query execution exceeded threshold")

Common Tag Conventions

Functional Tags

Identify system components and functions:

Go
// Authentication and authorization
logs.WithTags("auth", "login").Info("User logged in")
logs.WithTags("auth", "logout").Info("User logged out")
logs.WithTags("auth", "token_refresh").Debug("Token refreshed")
logs.WithTags("auth", "permission_denied").Warn("User lacks permission")

// Order processing
logs.WithTags("order", "creation").Info("Order created")
logs.WithTags("order", "payment").Error("Payment failed", err)
logs.WithTags("order", "shipping").Info("Order shipped")
logs.WithTags("order", "cancellation").Warn("Order cancelled")

// Database operations
logs.WithTags("database", "query").Trace("Executing query")
logs.WithTags("database", "connection").Debug("Connection opened")
logs.WithTags("database", "migration").Info("Running migration")

// API interactions
logs.WithTags("api", "request").Debug("API request sent")
logs.WithTags("api", "response").Debug("API response received")
logs.WithTags("api", "rate_limit").Warn("Rate limit approaching")

Severity/Importance Tags

Distinguish critical operations from routine ones:

Go
// High priority
logs.WithTags("critical", "security").Error("Unauthorized access attempt", err)
logs.WithTags("critical", "payment").Error("Payment processing failed", err)
logs.WithTags("critical", "data_loss").Critical("Data integrity check failed")

// Standard priority
logs.WithTags("standard", "info").Info("User action completed")
logs.WithTags("standard", "debug").Debug("Cache retrieved successfully")

// Low priority
logs.WithTags("internal", "debug").Trace("Internal state calculation")
logs.WithTags("internal", "optimization").Debug("Cache optimization completed")

Domain-Specific Tags

Organize by business domains:

Go
// E-commerce domain
logs.WithTags("ecommerce", "inventory").Info("Stock updated")
logs.WithTags("ecommerce", "pricing").Debug("Price calculated")
logs.WithTags("ecommerce", "checkout").Info("Checkout process started")

// User management domain
logs.WithTags("users", "registration").Info("User registered")
logs.WithTags("users", "profile").Debug("Profile information updated")
logs.WithTags("users", "preferences").Debug("User preferences saved")

// Notification domain
logs.WithTags("notification", "email").Info("Email sent")
logs.WithTags("notification", "sms").Warn("SMS delivery failed")
logs.WithTags("notification", "push").Debug("Push notification queued")

Fluent API with Tags

Tags with Other Features

Go
// Tags with context
logs.WithTags("payment", "processing").
    WithContext("amount", 99.99).
    WithContext("currency", "USD").
    Info("Processing payment")

// Tags with correlation ID
logs.WithTags("request", "handling").
    WithCorrelationID("req_abc123").
    WithContext("endpoint", "/api/orders").
    Debug("Processing request")

// Tags with exception
err := processPayment()
if err != nil {
    logs.WithTags("payment", "error", "critical").
        WithException(err).
        Error("Payment processing failed", err)
}

// Tags with user
logs.SetUser(&logs.AuthUser{ID: "user_123", Email: "user@example.com"})
logs.WithTags("auth", "action").
    WithContext("action", "login").
    Info("User logged in")

Practical Examples

Service Layer with Tags

Go
type PaymentService struct {
    gateway PaymentGateway
    repo    PaymentRepository
}

func (s *PaymentService) ProcessPayment(ctx context.Context, orderId string, amount float64) (string, error) {
    logs.WithTags("payment", "processing").
        WithContext("orderId", orderId).
        WithContext("amount", amount).
        Info("Starting payment processing")
    
    // Validate amount
    if amount <= 0 {
        logs.WithTags("payment", "validation").
            WithContext("amount", amount).
            Warn("Invalid payment amount")
        return "", fmt.Errorf("invalid amount")
    }
    
    // Call payment gateway
    transactionId, err := s.gateway.Charge(ctx, amount)
    if err != nil {
        logs.WithTags("payment", "gateway", "error").
            WithContext("amount", amount).
            WithException(err).
            Error("Payment gateway request failed", err)
        return "", err
    }
    
    // Save transaction
    err = s.repo.SaveTransaction(&Transaction{
        ID:      transactionId,
        OrderID: orderId,
        Amount:  amount,
    })
    if err != nil {
        logs.WithTags("payment", "storage", "error").
            WithContext("transactionId", transactionId).
            WithException(err).
            Error("Failed to save transaction", err)
        return "", err
    }
    
    logs.WithTags("payment", "success").
        WithContext("transactionId", transactionId).
        WithContext("amount", amount).
        Info("Payment processed successfully")
    
    return transactionId, nil
}

HTTP Handler with Tags

Go
func (h *OrderHandler) ListOrders(w http.ResponseWriter, r *http.Request) {
    logs.WithTags("api", "request", "orders_list").
        WithContext("method", r.Method).
        WithContext("path", r.URL.Path).
        Debug("Processing orders list request")
    
    // Parse query parameters
    page := r.URL.Query().Get("page")
    if page == "" {
        page = "1"
    }
    
    logs.WithTags("api", "pagination").
        WithContext("page", page).
        Trace("Parsed pagination parameters")
    
    // Fetch orders
    orders, err := h.service.GetOrders(page)
    if err != nil {
        logs.WithTags("api", "database", "error").
            WithContext("page", page).
            WithException(err).
            Error("Failed to fetch orders", err)
        http.Error(w, "Internal Server Error", http.StatusInternalServerError)
        return
    }
    
    logs.WithTags("api", "response", "orders_list").
        WithContext("count", len(orders)).
        Debug("Successfully retrieved orders")
    
    // Return response
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(orders)
}

Background Job with Tags

Go
func (w *Worker) ProcessOrders(ctx context.Context) error {
    logs.WithTags("job", "background", "orders").
        Info("Starting order processing job")
    
    orders, err := w.repo.GetPendingOrders()
    if err != nil {
        logs.WithTags("job", "background", "orders", "error").
            WithException(err).
            Error("Failed to fetch pending orders", err)
        return err
    }
    
    logs.WithTags("job", "background", "orders").
        WithContext("count", len(orders)).
        Debug("Processing pending orders")
    
    for _, order := range orders {
        err := w.processOrder(ctx, order)
        if err != nil {
            logs.WithTags("job", "background", "orders", "error").
                WithContext("orderId", order.ID).
                WithException(err).
                Warn("Failed to process order")
            continue
        }
        
        logs.WithTags("job", "background", "orders", "success").
            WithContext("orderId", order.ID).
            Trace("Order processed successfully")
    }
    
    logs.WithTags("job", "background", "orders").
        Info("Order processing job completed")
    
    return nil
}

Database Operations with Tags

Go
func (r *OrderRepository) GetOrderByID(ctx context.Context, orderId string) (*Order, error) {
    logs.WithTags("database", "query", "select").
        WithContext("orderId", orderId).
        Trace("Executing select query")
    
    query := "SELECT id, customer_id, total, status FROM orders WHERE id = $1"
    row := r.db.QueryRowContext(ctx, query, orderId)
    
    var order Order
    err := row.Scan(&order.ID, &order.CustomerID, &order.Total, &order.Status)
    if err != nil {
        if err == sql.ErrNoRows {
            logs.WithTags("database", "query", "not_found").
                WithContext("orderId", orderId).
                Debug("Order not found")
            return nil, fmt.Errorf("order not found")
        }
        
        logs.WithTags("database", "query", "error").
            WithContext("orderId", orderId).
            WithException(err).
            Error("Query execution failed", err)
        return nil, err
    }
    
    logs.WithTags("database", "query", "success").
        WithContext("orderId", orderId).
        Trace("Order retrieved successfully")
    
    return &order, nil
}

Best Practices

Tag Best Practices

  • Use consistent tag naming across your codebase (e.g., always use "auth" not "authentication")
  • Keep tags concise - use short, meaningful labels
  • Combine tags logically - group related concepts (e.g., "payment" with "processing")
  • Use lowercase for all tags for consistency
  • Avoid high-cardinality tags - don't use dynamic values (use context instead)
  • Document tag conventions in your team's logging guidelines
  • Limit tags per log - typically 2-4 tags per entry

Tags vs Context

Use tags for static, predefined categories (auth, payment, database). Use context for dynamic, specific values (userId, orderId, duration).

Next Steps

Previous
Metadata & Context