Learn / Go Service Engineering
Observability and Operational Errors
Make service failures visible with structured logs, typed operational errors, request IDs, and safe response mapping.
Course: Go Service Engineering. Level: Intermediate. Topic: Reliable services.
Stage: advanced - Advanced operations - Go observability and operational error handling. Turn runtime failures into structured signals that help operators distinguish client errors, dependency failures, and saturation.
Outcomes
- Log with stable fields.
- Map expected failures to client-safe JSON.
- Connect request IDs across handler, service, and worker logs.
Concepts
- slog
- error wrapping
- request id
- operational error
Concept flow
Show how go observability and operational error handling moves from trigger to implementation outcome in Go Services.
- HTTP request
- Request ID middleware
- Service error
- slog record
- JSON response
Session flow
- Model slog (concept, 11 min) — Name the decisions behind slog before writing code.
- Log with stable fields.
- Explain where slog belongs in ticket processing platform.
- Build the vertical slice (walkthrough, 20 min) — Implement the smallest useful slice in internal/http/errors.go.
- Map expected failures to client-safe JSON.
- Connect error wrapping to a working example.
- Verify and harden (exercise, 13 min) — Assert the client response does not leak internals.
- Connect request IDs across handler, service, and worker logs.
- Record one risk or follow-up before moving on.
Code example
Go in internal/http/errors.go.
package httpapi
import (
"encoding/json"
"errors"
"log/slog"
"net/http"
)
type AppError struct {
Code string
StatusCode int
Err error
}
func (e AppError) Error() string {
return e.Code
}
func (e AppError) Unwrap() error {
return e.Err
}
func writeError(w http.ResponseWriter, r *http.Request, err error) {
var appErr AppError
if !errors.As(err, &appErr) {
appErr = AppError{Code: "internal_error", StatusCode: http.StatusInternalServerError, Err: err}
}
slog.ErrorContext(r.Context(), "request failed", "code", appErr.Code, "error", appErr.Err)
writeJSON(w, appErr.StatusCode, map[string]string{"error": appErr.Code})
}
func writeJSON(w http.ResponseWriter, status int, payload any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(payload)
}
Walkthrough examples
- Observability and Operational Errors in a ticket processing platform — A team is extending a small Go service plus worker and needs this lesson's pattern to be clear enough for review, testing, and future maintenance.
- File: internal/http/errors.go
- File: tests/observability-and-operational-errors.spec
- File: docs/go-services/observability-and-operational-errors.md
- Start from the provided Go snippet and make the intent visible in names and boundaries.
- Apply the checklist item "Errors have stable codes" before adding extra behavior.
- Write down how the implementation changes when error wrapping fails or becomes slow.
Practice
- Wrap one repository error with an operational code.
- Log request id and operation name for one failed path.
- Assert the client response does not leak internals.
Checklist
- Errors have stable codes
- Logs include request context
- Responses are client-safe
- Unexpected errors are observable
Quiz prompts
- Why map internal errors to stable public codes? — Public error contracts and private operational context serve different audiences.
- A teammate wants to hide slog inside a convenient helper. What should you check first? — Place slog at the boundary that keeps ticket processing platform behavior explicit, testable, and reviewable.
- Which artifact best proves this Go Services lesson is ready for review? — Production-ready learning needs evidence: a test, trace, command, screenshot, or log that catches the risk again.
- Advanced operations: a teammate says the happy path works, but "Structured slog fields" is still implicit. What should you ask for before merging? — Structured slog fields belongs in the advanced stage only when the decision is visible, testable, and tied to a realistic failure mode.
- A reviewer has five minutes to evaluate this advanced Go Services slice. Which evidence is strongest? — Create an advanced Go operations layer with structured logs, error taxonomy, status mapping, and a short investigation guide.
Flashcards
- Advanced operations: what decision does "Structured slog fields" force you to make? Attach route, request ID, job ID, duration, and dependency context without leaking secrets. Evidence prompt: Capture one sanitized structured log from a failed dependency call.
- Advanced operations: what decision does "Operational error taxonomy" force you to make? Separate invalid input, not found, conflict, timeout, dependency, and saturation failures. Evidence prompt: Map three error classes to status codes and log levels.
- Advanced operations: what decision does "Metric and log correlation" force you to make? Choose counters, durations, and log fields that let incidents be investigated quickly. Evidence prompt: Name the three signals you would inspect for a latency spike.
- In Go Services, what should you remember about slog? slog matters here because it supports "Log with stable fields.".
- In Go Services, what should you remember about error wrapping? error wrapping matters here because it supports "Map expected failures to client-safe JSON.".
- In Go Services, what should you remember about request id? request id matters here because it supports "Connect request IDs across handler, service, and worker logs.".
- In Go Services, what should you remember about operational error? operational error matters here because it supports "Log with stable fields.".
Labs
- Ship a observability and operational errors slice — Extend a small Go service plus worker with a small but reviewable feature that proves the lesson's architecture in code.
- Create an advanced Go operations layer with structured logs, error taxonomy, status mapping, and a short investigation guide.
- Capture one sanitized structured log from a failed dependency call.
- Map three error classes to status codes and log levels.
- Name the three signals you would inspect for a latency spike.
- Wrap one repository error with an operational code.
- Log request id and operation name for one failed path.
- The lab demonstrates the advanced operations outcome without skipping earlier contract evidence.
- Each subtopic has a concrete artifact: Structured slog fields, Operational error taxonomy, Metric and log correlation.
- The review notes explain how this level changes ownership, verification, or operational risk.
Challenge
- Review-ready observability and operational errors (Core) — Create an advanced Go operations layer with structured logs, error taxonomy, status mapping, and a short investigation guide.
- All checklist items are either implemented or documented with a reason.
- The change can be understood from internal/http/errors.go plus one short note.
- The concept diagram names ownership, failure handling, and verification points.
- A teammate could run the verification steps without asking for hidden context.
Canonical lesson URL