Skip to content

Latest commit

History

144 Commits

Folders and files

NameName
Last commit message
Last commit date

ColdBrew

CIGo Report CardGoDocLicense: MIT

A Go microservice framework for building production-grade gRPC services with built-in observability, resilience, and HTTP gateway support.

ColdBrew powers 100+ microservices serving 70k+ QPS each in production. It provides a batteries-included foundation so you can focus on business logic instead of boilerplate.

Packages

ColdBrew is a collection of composable packages:

PackageDescription
coregRPC server, HTTP gateway, health checks, Prometheus metrics, graceful shutdown
interceptorsChained gRPC interceptors: logging, tracing, Prometheus, circuit breaking, retries
errorsEnhanced errors with stack traces, gRPC status codes, error notification
logStructured logging with pluggable backends (zap, logrus, go-kit)
tracingDistributed tracing: OpenTelemetry, OpenTracing, NewRelic
optionsRequest-scoped key-value metadata via context
grpcpoolRound-robin gRPC connection pool
data-builderDependency injection with automatic resolution and parallel execution
workersBackground worker lifecycle with panic recovery, restart, and tracing

Quick Start

# Generate a new service from the template
pip install cookiecutter
cookiecutter gh:go-coldbrew/cookiecutter-coldbrew
# Build and runcd YourApp
make run

Your service starts with gRPC on :9090, HTTP gateway on :9091, Prometheus metrics at /metrics, and health checks at /healthcheck and /readycheck.

Documentation


API Reference

core

import"github.com/go-coldbrew/core"

Package core is the main entry point for the ColdBrew microservice framework. It creates a gRPC server with an HTTP gateway (via grpc-gateway), wires health checks, Prometheus metrics, pprof endpoints, signal handling, graceful shutdown, and all interceptors. Services implement the CBService interface to register their gRPC and HTTP handlers.

ColdBrew builds on proven open-source libraries:

Usage

cb := core.New(config.Config{
GRPCPort: "9090",
HTTPPort: "9091",
ServiceName: "my-service",
})
cb.SetService(myService)
cb.Run()

For full documentation, visit https://docs.coldbrew.cloud

Index

Constants

SupportPackageIsVersion1 is a compile-time assertion constant. Downstream packages reference this to enforce version compatibility.

constSupportPackageIsVersion1=true

funcAddWorkerRunOptions(opts...workers.RunOption)

AddWorkerRunOptions appends [workers.RunOption] values applied when core.Run() invokes [workers.Run]. Use this to configure framework-wide worker behavior: metrics, run-level interceptors, default jitter, etc. Must be called during init, before Run(). Not concurrency-safe.

By default, core wires a Prometheus metrics implementation using the service's APP_NAME unless DISABLE_PROMETHEUS=true or APP_NAME is empty. Pass [workers.WithMetrics] here to override that default; a later WithMetrics wins because workers.WithMetrics overwrites runConfig.metrics on each apply.

funcInitializeVTProto()

InitializeVTProto initializes the vtproto package for use with the service

https://github.com/planetscale/vtprotobuf?tab=readme-ov-file#mixing-protobuf-implementations-with-grpc

funcOTELMeterProvider() otelmetric.MeterProvider

OTELMeterProvider returns the global OTel MeterProvider. This is a convenience accessor for code that needs the interface type.

funcRegisterHTTPMarshaler(mimestring, m runtime.Marshaler)

RegisterHTTPMarshaler registers a runtime.Marshaler for the given MIME type on the HTTP gateway. Equivalent to RegisterServeMuxOption(runtime.WithMarshalerOption(mime, m)).

To override the gateway's default fallback for unregistered Content-Types (which is protojson via runtime.JSONPb), register for runtime.MIMEWildcard.

Must be called before core.Run(). Not safe for concurrent registration.

funcRegisterServeMuxOption(opt runtime.ServeMuxOption)

RegisterServeMuxOption appends a runtime.ServeMuxOption that initHTTP passes to runtime.NewServeMux. Registered options are applied AFTER core's built-ins (the incoming-header matcher derived from HTTPHeaderPrefixes, the application/proto and application/protobuf marshalers, and the span-route middleware), so:

  • Last-write-wins options — WithMarshalerOption for a given MIME, WithErrorHandler, WithRoutingErrorHandler, WithIncomingHeaderMatcher — can intentionally override core's defaults. Overriding the incoming header matcher disables the HTTPHeaderPrefixes wiring; reimplement it yourself if you still need that behavior.
  • Additive options — WithMiddlewares, WithMetadata, WithForwardResponseOption — stack with core's.

Must be called before core.Run() (typically from a service's PreStart hook). Not safe for concurrent registration.

funcSetOTELGRPCClientOptions(opts...otelgrpc.Option)

Deprecated: Use SetOTELOptions instead. Only applies when OTEL_USE_LEGACY_INSTRUMENTATION=true.

funcSetOTELGRPCServerOptions(opts...otelgrpc.Option)

Deprecated: Use SetOTELOptions instead. Only applies when OTEL_USE_LEGACY_INSTRUMENTATION=true.

funcSetOTELOptions(opts grpcotel.Options)

SetOTELOptions configures the native gRPC stats/opentelemetry integration. Must be called during init, before the gRPC server starts. When set, processConfig() will NOT overwrite these with auto-built options.

funcSetupAutoMaxProcs()

SetupAutoMaxProcs sets up the GOMAXPROCS to match Linux container CPU quota This is used to set the GOMAXPROCS to the number of CPUs allocated to the container

funcSetupEnvironment(envstring)

SetupEnvironment sets the environment This is used to identify the environment in Sentry and New Relic env is the environment to set for the service (e.g. prod, staging, dev)

funcSetupHystrixPrometheus()

SetupHystrixPrometheus sets up the hystrix metrics This is a workaround for hystrix-go not supporting the prometheus registry It uses sync.Once to ensure the Prometheus collectors are only registered once, since duplicate registration panics.

funcSetupLogger(logLevelstring, jsonlogsbool) error

SetupLogger sets up the logger using ColdBrew's slog-native Handler. It calls log.SetDefault which also wires slog.SetDefault, so native slog.LogAttrs calls automatically get ColdBrew context fields. logLevel is the log level to set for the logger jsonlogs is a boolean to enable or disable json logs

funcSetupNROpenTelemetry(serviceName, license, versionstring, ratiofloat64) error

SetupNROpenTelemetry sets up OpenTelemetry tracing with New Relic

This function configures OpenTelemetry to send traces to New Relic's OTLP endpoint. It's a convenience wrapper around SetupOpenTelemetry with New Relic-specific configuration.

Parameters:

  • serviceName: the name of the service
  • license: the New Relic license key
  • version: the version of the service
  • ratio: the sampling ratio to use for traces (0.0 to 1.0)

funcSetupNewRelic(serviceName, apiKeystring, tracingbool) error

SetupNewRelic sets up the New Relic tracing and monitoring agent for the service It uses the New Relic Go Agent to send traces to New Relic One APM and Insights serviceName is the name of the service apiKey is the New Relic license key tracing is a boolean to enable or disable tracing

funcSetupOTELMetrics(configOTLPConfig, interval time.Duration) (*sdkmetric.MeterProvider, error)

SetupOTELMetrics creates a MeterProvider with an OTLP gRPC exporter that reuses the same resource as the TracerProvider (set by SetupOpenTelemetry). The MeterProvider is set as the global OTel MeterProvider.

Call this after SetupOpenTelemetry so the shared resource is available.

funcSetupOpenTelemetry(configOTLPConfig) error

SetupOpenTelemetry sets up OpenTelemetry tracing with a generic OTLP exporter.

It configures a TracerProvider with the given sampling ratio and OTLP backend, sets it as the global provider, and stores it for graceful shutdown.

Example usage with Jaeger:

config := OTLPConfig{
Endpoint: "localhost:4317",
ServiceName: "my-service",
ServiceVersion: "v1.0.0",
SamplingRatio: 0.1,
Insecure: true, // for local development
}
err := SetupOpenTelemetry(config)

Example usage with Honeycomb:

config := OTLPConfig{
Endpoint: "api.honeycomb.io:443",
Headers: map[string]string{"x-honeycomb-team": "your-api-key"},
ServiceName: "my-service",
ServiceVersion: "v1.0.0",
SamplingRatio: 0.2,
}
err := SetupOpenTelemetry(config)

funcSetupReleaseName(relstring)

SetupReleaseName sets the release name This is used to identify the release in Sentry rel is the release name to set for the service (e.g. v1.0.0)

funcSetupSentry(dsnstring)

SetupSentry sets up the Sentry notifier It uses the Sentry HTTP Transport to send errors to Sentry server dsn is the Sentry DSN to use for sending errors

type CB

CB is the interface that wraps coldbrew methods.

typeCBinterface {
// SetService sets the service.SetService(CBService) error// Run runs the service.// Run is blocking. It returns an error if the service fails. Otherwise, it returns nil.Run() error// SetOpenAPIHandler sets the OpenAPI handler.SetOpenAPIHandler(http.Handler)
// Stop stops the service.// Stop is blocking. It returns an error if the service fails. Otherwise, it returns nil.// duration is the duration to wait for the service to stop.Stop(time.Duration) error
}

func New

funcNew(c config.Config) CB

New creates a new ColdBrew object It takes a config object and returns a CB interface The CB interface is used to start and stop the server The CB interface also provides a way to add services to the server The services are added using the AddService method The services are started and stopped in the order they are added

CBGracefulStopper is the interface that wraps the graceful stop method.

typeCBGracefulStopperinterface {
// FailCheck set if the service is ready to stop.// FailCheck is called by the core package.FailCheck(bool)
}

CBPostStarter is implemented by services that need to act after servers are listening. Use this for registering with service discovery, logging startup banners, or notifying external systems.

typeCBPostStarterinterface {
PostStart(ctx context.Context)
}

CBPostStopper is implemented by services that need final cleanup after all servers and workers have stopped. Use this for closing audit logs, pushing final metrics, or any cleanup that must happen after all in-flight work is complete.

typeCBPostStopperinterface {
PostStop(ctx context.Context)
}

CBPreStarter is implemented by services that need setup before servers start. Called during Run(), before initGRPC/initHTTP. If PreStart returns an error, startup is aborted. Use this for connecting to databases, message brokers, configuring interceptors, or any setup that must complete before the service accepts traffic.

typeCBPreStarterinterface {
PreStart(ctx context.Context) error
}

CBPreStopper is implemented by services that need to act before graceful shutdown begins. Use this for deregistering from load balancers, flushing buffers, or notifying external systems of impending shutdown.

typeCBPreStopperinterface {
PreStop(ctx context.Context)
}

CBService is the interface that wraps service methods used in ColdBrew. InitHTTP initializes the HTTP server. InitGRPC initializes the gRPC server. InitHTTP and InitGRPC are called by the core package.

typeCBServiceinterface {
// InitHTTP initializes the HTTP server// mux is the HTTP server mux to register the service.// endpoint is the gRPC endpoint to connect.// opts is the gRPC dial options used to connect to the endpoint.InitHTTP(ctx context.Context, mux*runtime.ServeMux, endpointstring, opts []grpc.DialOption) error// InitGRPC initializes the gRPC server// server is the gRPC server to register the service.InitGRPC(ctx context.Context, server*grpc.Server) error
}

CBStopper is the interface that wraps the stop method.

typeCBStopperinterface {
// Stop stops the service.// Stop is called by the core package.Stop()
}

CBWorkerProvider is implemented by services that run background workers. Workers are started after initGRPC/initHTTP and stopped during graceful shutdown. Called once during Run(). Workers are managed by the go-coldbrew/workers package with automatic panic recovery, configurable restart, and structured shutdown via suture supervisor trees.

typeCBWorkerProviderinterface {
Workers() []*workers.Worker
}

OTLPConfig holds configuration for OpenTelemetry OTLP exporter

This struct provides a flexible way to configure OpenTelemetry tracing with any OTLP-compatible backend (e.g., Jaeger, Honeycomb, New Relic, etc.)

typeOTLPConfigstruct {
// Endpoint is the OTLP gRPC endpoint to send traces to// Examples: "localhost:4317", "otlp.nr-data.net:4317", "api.honeycomb.io:443"Endpointstring// Headers are custom headers to send with each request// Examples:// New Relic: {"api-key": "your-license-key"}// Honeycomb: {"x-honeycomb-team": "your-api-key"}Headersmap[string]string// ServiceName is the name of the service sending tracesServiceNamestring// ServiceVersion is the version of the serviceServiceVersionstring// SamplingRatio is the ratio of traces to sample (0.0 to 1.0)// 1.0 means sample all traces, 0.1 means sample 10% of tracesSamplingRatiofloat64// Compression specifies the compression type (e.g., "gzip", "none")// If empty, defaults to "gzip"Compressionstring// Insecure disables TLS verification for the connection// Only use this for local development or testingInsecurebool
}

SSEMarshaler is a runtime.Marshaler that emits Server-Sent Events (text/event-stream) frames for server-streaming gateway RPCs. It lets browser EventSource clients consume streaming RPCs directly — useful for AI/LLM token streaming and other long-running progressive responses.

Each Marshal call returns "data: <json>" with no trailing newline; the Delimiter ("\n\n") terminates each SSE frame per the SSE spec. The JSON payload uses protojson via the embedded runtime.JSONPb, so field naming matches the gateway's default JSON responses.

Wire it up from a service's PreStart hook:

core.RegisterHTTPMarshaler("text/event-stream", &core.SSEMarshaler{})

Clients then opt in by sending Accept: text/event-stream on the gateway URL. The newHTTPCompressionWrapper excludes text/event-stream from gzip/zstd compression so frames reach the client in real time (compressed SSE is buffered by many HTTP intermediaries).

SSE is server-to-client only: Unmarshal and NewDecoder return an error.

Per-field protojson options (EmitUnpopulated, UseProtoNames, etc.) can be set by initializing the embedded JSONPb directly:

&core.SSEMarshaler{JSONPb: runtime.JSONPb{
MarshalOptions: protojson.MarshalOptions{EmitUnpopulated: true},
}}
typeSSEMarshalerstruct {
runtime.JSONPb
}

func (*SSEMarshaler) ContentType

func (*SSEMarshaler) ContentType(_any) string

ContentType always returns "text/event-stream".

func (*SSEMarshaler) Delimiter

func (*SSEMarshaler) Delimiter() []byte

Delimiter returns "\n\n", which terminates one SSE frame. A fresh slice is returned per call so callers cannot mutate the framing for other SSEMarshaler instances.

func (*SSEMarshaler) Marshal

func (s*SSEMarshaler) Marshal(vany) ([]byte, error)

Marshal returns "data: <json>" with no trailing newline. Frame termination is supplied by Delimiter; the gateway writes Marshal output followed by Delimiter for each streamed message.

Newlines inside the JSON payload (when the embedded runtime.JSONPb is configured with MarshalOptions.Multiline or Indent) are turned into continuation lines: each line of the payload starts with "data: " as the SSE spec requires, otherwise EventSource truncates the frame after the first line.

func (*SSEMarshaler) NewDecoder

func (*SSEMarshaler) NewDecoder(_ io.Reader) runtime.Decoder

NewDecoder returns a decoder that always errors, for the same reason as Unmarshal.

func (*SSEMarshaler) NewEncoder

func (s*SSEMarshaler) NewEncoder(w io.Writer) runtime.Encoder

NewEncoder returns an encoder that writes "data: <json>\n\n" per Encode call.

func (*SSEMarshaler) StreamContentType

func (*SSEMarshaler) StreamContentType(_any) string

StreamContentType matches ContentType so server-streaming responses also advertise text/event-stream. Gateway prefers this over ContentType when implemented (see runtime.ForwardResponseStream).

func (*SSEMarshaler) Unmarshal

func (*SSEMarshaler) Unmarshal(_ []byte, _any) error

Unmarshal returns an error: SSE is a server-to-client format and the gateway never reads SSE bodies from inbound requests.

Generated by gomarkdoc

About

Go microservice framework — gRPC server, HTTP gateway, observability, graceful shutdown

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages