Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,71 @@ made along with its context and consequences.
>
> Also, each boundary context and service has its own ADR. You can find them in the relevant sections.

### Core Packages

The ShortLink project provides a comprehensive set of reusable packages that implement modern software engineering practices and clean architecture principles.

#### Observability Package (`pkg/observability`)

Advanced observability capabilities with comprehensive tracing, metrics, and logging support:

- **Enhanced Tracing with FlightRecorder**: Implements Go 1.25 `trace.FlightRecorder` for "perfect tracing"
- **Domain Layer**: Core business logic and interfaces (`pkg/observability/traicing/domain/`)
- `recorder.go` - Core recorder interfaces and value objects
- `errors.go` - Domain-specific error definitions
- **Application Layer**: Use cases and service orchestration (`pkg/observability/traicing/application/`)
- `service.go` - High-level recorder operations and business workflows
- **Infrastructure Layer**: External integrations and implementations (`pkg/observability/traicing/infrastructure/`)
- `recorder.go` - Go 1.25 FlightRecorder adapter
- `repository.go` - File system and storage implementations
- `events.go` - Logging and monitoring event handlers
- **Factory Pattern**: Dependency injection and component wiring (`pkg/observability/traicing/factory.go`)

**Key Features:**
- **Clean Architecture**: Follows hexagonal architecture with clear separation of concerns
- **Perfect Tracing**: Continuous, low-overhead tracing with configurable rolling buffer (default: 1 minute, 3MB)
- **Professional Error Handling**: Comprehensive error types and validation
- **Thread-Safe Operations**: Mutex-protected operations with proper resource management
- **Multiple Storage Backends**: Filesystem and in-memory storage implementations
- **Event-Driven Architecture**: Composite event handling for logging, metrics, and monitoring
- **Dependency Injection**: Factory pattern for clean component assembly

**Configuration Options:**
```bash
FLIGHT_RECORDER_ENABLED=true # Enable/disable flight recorder
FLIGHT_RECORDER_MIN_AGE=1m # Minimum trace data retention
FLIGHT_RECORDER_MAX_BYTES=3145728 # Maximum buffer size (3MB)
```

**Usage Example:**
```go
// Create factory with configuration
config := traicing.DefaultFactoryConfig(logger)
factory, err := traicing.NewFactory(config)

// Create service with all dependencies wired
service, err := factory.CreateRecorderService()

// Start recording
err = service.StartRecording(ctx)

// Capture trace on significant events
traceID, err := service.CaptureTrace(ctx, "error_occurred")
```


#### Additional Packages

- **Database (`pkg/db`)**: Multi-database support with connection pooling and health checks
- **Dependency Injection (`pkg/di`)**: Structured dependency injection with lifecycle management
- **HTTP Utilities (`pkg/http`)**: Middleware, routing, and server utilities
- **Concurrency (`pkg/concurrency`)**: Advanced concurrency patterns and utilities
- **Caching (`pkg/cache`)**: Multi-backend caching with TTL and eviction policies
- **Message Queue (`pkg/mq`)**: Multi-provider message queue abstractions
- **Pattern Implementations (`pkg/pattern`)**: Common software patterns (CQRS, Event Sourcing, etc.)

Each package follows clean architecture principles with proper separation of concerns, comprehensive testing, and professional documentation.

### License

> [!WARNING]
Expand Down
11 changes: 5 additions & 6 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-2023080216373
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.4-20250130201111-63bb56e20495.1/go.mod h1:novQBstnxcGpfKf8qGRATqn1anQKwMJIbH5Q581jibU=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250425153114-8976f5be98c1.1 h1:YhMSc48s25kr7kv31Z8vf7sPUIq5YJva9z1mn/hAt0M=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250425153114-8976f5be98c1.1/go.mod h1:avRlCjnFzl98VPaeCtJ24RrV/wwHFzB8sWXhj26+n/U=
buf.build/gen/go/shortlink-org/shortlink-link-link/protocolbuffers/go v1.36.9-20240420204150-bbba30c24796.1/go.mod h1:4bQ0sc4V6ggyU9AKG+pDG7di7ksHD+Spvaiwanj5JHI=
buf.build/go/protovalidate v0.12.0 h1:4GKJotbspQjRCcqZMGVSuC8SjwZ/FmgtSuKDpKUTZew=
buf.build/go/protovalidate v0.12.0/go.mod h1:q3PFfbzI05LeqxSwq+begW2syjy2Z6hLxZSkP1OH/D0=
cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
Expand Down Expand Up @@ -1449,7 +1448,6 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 h1:8nn+rsCvTq9axyEh382S0PFLBeaFwNsT43IrPWzctRU=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1/go.mod h1:viRWSEhtMZqz1rhwmOVKkWl6SwmVowfL9O2YR5gI2PE=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0=
github.com/IBM/sarama v1.46.1/go.mod h1:ipyOREIx+o9rMSrrPGLZHGuT0mzecNzKd19Quq+Q8AA=
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab h1:UKkYhof1njT1/xq4SEg5z+VpTgjmNeHwPGRQl7takDI=
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
Expand Down Expand Up @@ -1953,7 +1951,6 @@ github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgx
github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc=
github.com/geldata/gel-go v1.4.3/go.mod h1:M3ssAJdJH5OjwJnFda7mgp3tBDHoFC1zcYjZBwDueYY=
github.com/getsentry/sentry-go v0.11.0/go.mod h1:KBQIxiZAetw62Cj8Ri964vAEWVdgfaUCn30Q3bCvANo=
github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
Expand Down Expand Up @@ -2231,7 +2228,6 @@ github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCp
github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak=
github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU=
github.com/grafana/pyroscope-go/godeltaprof v0.1.4/go.mod h1:1HSPtjU8vLG0jE9JrTdzjgFqdJ/VgN7fvxBNq3luJko=
github.com/graph-gophers/graphql-go v1.8.0/go.mod h1:23olKZ7duEvHlF/2ELEoSZaY1aNPfShjP782SOoNTyM=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
Expand Down Expand Up @@ -2828,6 +2824,7 @@ github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1
github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50=
github.com/raeperd/recvcheck v0.1.2/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU=
github.com/redis/rueidis/mock v1.0.60/go.mod h1:XXT8Pl1zgKAu3IjNhdb4M0Z4UjZQyKe72f5kR6RJSZI=
github.com/redis/rueidis/mock v1.0.66/go.mod h1:rNgRslLT8XAS2lenZP87epjz/PEbiNEp2fI11pNhkUI=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
Expand Down Expand Up @@ -3191,6 +3188,7 @@ go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0 h1:TaB+1rQhddO1sF71MpZOZAuSPW1klK2M8XxfrBMfK7Y=
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0/go.mod h1:78XhIg8Ht9vR4tbLNUhXsiOnE2HOuSeKAiAcoVQEpOY=
Expand All @@ -3214,6 +3212,7 @@ go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdga
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
Expand All @@ -3224,6 +3223,7 @@ go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g5
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
Expand All @@ -3242,17 +3242,16 @@ go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+M
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
go.temporal.io/api v1.53.0/go.mod h1:iaxoP/9OXMJcQkETTECfwYq4cw/bj4nwov8b3ZLVnXM=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
Expand Down
18 changes: 17 additions & 1 deletion pkg/di/pkg/traicing/traicing.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,34 @@ import (
"github.com/shortlink-org/shortlink/pkg/observability/traicing"
)

// New returns a new instance of the TracerProvider.
// New returns a new instance of the TracerProvider with Go 1.25 FlightRecorder support.
//
//nolint:ireturn // It's make by specification
func New(ctx context.Context, log logger.Logger) (trace.TracerProvider, func(), error) {
viper.SetDefault("TRACER_URI", "localhost:4317") // Tracing addr:host
viper.SetDefault("PYROSCOPE_URI", "http://pyroscope.pyroscope:4040") // Pyroscope addr:host

// Flight Recorder defaults
viper.SetDefault("FLIGHT_RECORDER_ENABLED", true)
viper.SetDefault("FLIGHT_RECORDER_MIN_AGE", "1m")
viper.SetDefault("FLIGHT_RECORDER_MAX_BYTES", 3<<20) // 3MB

// Configure Flight Recorder
var flightRecorderConfig *traicing.FlightRecorderConfig
if viper.GetBool("FLIGHT_RECORDER_ENABLED") {
flightRecorderConfig = &traicing.FlightRecorderConfig{
Enabled: true,
MinAge: viper.GetDuration("FLIGHT_RECORDER_MIN_AGE"),
MaxBytes: viper.GetInt64("FLIGHT_RECORDER_MAX_BYTES"),
}
}

config := traicing.Config{
ServiceName: viper.GetString("SERVICE_NAME"),
ServiceVersion: viper.GetString("SERVICE_VERSION"),
URI: viper.GetString("TRACER_URI"),
PyroscopeURI: viper.GetString("PYROSCOPE_URI"),
FlightRecorder: flightRecorderConfig,
}

tracer, tracerClose, err := traicing.Init(ctx, config, log)
Expand Down
21 changes: 20 additions & 1 deletion pkg/observability/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,28 @@
This package provides observability primitives for the application:

- `monitoring` - provides a Prometheus metrics registry and a HTTP handler for exposing metrics
- `tracing` - provides a Tracing provider for OpenTelemetry
- `tracing` - provides a Tracing provider for OpenTelemetry with Go 1.25 FlightRecorder support
- `logging` - provides a structured logger

### Tracing Package

The `tracing` package offers comprehensive observability capabilities including:

- **OpenTelemetry Integration**: Full OTLP tracing support with automatic span collection
- **Go 1.25 FlightRecorder**: Continuous, low-overhead tracing with rolling buffer for perfect tracing
- **Automatic Trace Capture**: Captures traces on errors, panics, and user-defined signals
- **Environment Configuration**: Configurable via environment variables or code
- **Middleware Support**: Easy integration with existing application code

#### FlightRecorder Features

- **Perfect Tracing**: Always-available trace data for post-mortem analysis
- **Low Overhead**: In-memory ring buffer with configurable retention (default: 1 minute, 3MB)
- **Production Ready**: Thread-safe operations with comprehensive error handling
- **Signal Support**: Manual trace capture via SIGUSR1/SIGUSR2 signals
- **Health Monitoring**: Built-in health check functionality


### References

- [uptrace](https://uptrace.dev/opentelemetry/) - more articles and tips
Loading
Loading