{"id":37599988,"url":"https://github.com/quiqupltd/quiqupgo","last_synced_at":"2026-01-16T10:02:14.669Z","repository":{"id":332150476,"uuid":"1132602788","full_name":"quiqupltd/quiqupgo","owner":"quiqupltd","description":"Reusable uber/fx modules for Go microservices, providing standardized infrastructure for tracing, logging, database, temporal workflows, pub/sub messaging, and HTTP middleware.","archived":false,"fork":false,"pushed_at":"2026-01-12T20:27:34.000Z","size":150,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"dev","last_synced_at":"2026-01-12T22:24:36.954Z","etag":null,"topics":["fx","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/quiqupltd.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-12T07:37:27.000Z","updated_at":"2026-01-12T20:25:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/quiqupltd/quiqupgo","commit_stats":null,"previous_names":["quiqupltd/quiqupgo"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/quiqupltd/quiqupgo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quiqupltd%2Fquiqupgo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quiqupltd%2Fquiqupgo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quiqupltd%2Fquiqupgo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quiqupltd%2Fquiqupgo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/quiqupltd","download_url":"https://codeload.github.com/quiqupltd/quiqupgo/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quiqupltd%2Fquiqupgo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478049,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T06:30:42.265Z","status":"ssl_error","status_checked_at":"2026-01-16T06:30:16.248Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fx","golang"],"created_at":"2026-01-16T10:02:14.069Z","updated_at":"2026-01-16T10:02:14.660Z","avatar_url":"https://github.com/quiqupltd.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Quiqup Shared GO\n\n![Coverage](https://storage.googleapis.com/quiqup-public-assets/coverbadges/quiqupltd/quiqupgo/coverage.svg)\n\nReusable [uber/fx](https://github.com/uber-go/fx) modules for Go microservices, providing standardized infrastructure for tracing, logging, database, temporal workflows, pub/sub messaging, and HTTP middleware.\n\n## Features\n\n- **Modular Design**: Import only the modules you need\n- **Per-Module Configuration**: Each module defines its own config interface - no monolithic global config\n- **OpenTelemetry Native**: Full OTEL integration for tracing, metrics, and logging\n- **Testing Utilities**: Every module includes test helpers (NoopModule, MockModule, BufferLogger)\n- **Uber/fx Integration**: Seamless dependency injection with lifecycle management\n\n## Installation\n\n```bash\ngo get github.com/quiqupltd/quiqupgo\n```\n\n## Available Modules\n\n| Module | Package | Description |\n|--------|---------|-------------|\n| **Tracing** | `github.com/quiqupltd/quiqupgo/tracing` | OpenTelemetry tracing + metrics |\n| **Logger** | `github.com/quiqupltd/quiqupgo/logger` | Structured logging with zap + OTEL |\n| **Temporal** | `github.com/quiqupltd/quiqupgo/temporal` | Temporal workflow client |\n| **GORM** | `github.com/quiqupltd/quiqupgo/gormfx` | GORM database with OTEL plugin |\n| **Kafka** | `github.com/quiqupltd/quiqupgo/kafka` | Kafka messaging with tracing |\n| **Middleware** | `github.com/quiqupltd/quiqupgo/middleware` | HTTP tracing middleware (Echo/net/http) |\n| **Encore Middleware** | `github.com/quiqupltd/quiqupgo/middleware/encore` | Encore.dev tracing integration |\n\n## Quick Start\n\n### Minimal Example (Logger Only)\n\n```go\npackage main\n\nimport (\n    \"github.com/quiqupltd/quiqupgo/logger\"\n    \"go.uber.org/fx\"\n    \"go.uber.org/zap\"\n)\n\nfunc main() {\n    fx.New(\n        // Provide logger config\n        fx.Provide(func() logger.Config {\n            return \u0026logger.StandardConfig{\n                ServiceName: \"my-service\",\n                Environment: \"development\",\n            }\n        }),\n\n        // Include logger module\n        logger.Module(),\n\n        // Use the logger\n        fx.Invoke(func(log *zap.Logger) {\n            log.Info(\"application started\")\n        }),\n    ).Run()\n}\n```\n\n### Full Stack Example (All Modules)\n\n```go\npackage main\n\nimport (\n    \"database/sql\"\n\n    \"github.com/quiqupltd/quiqupgo/gormfx\"\n    \"github.com/quiqupltd/quiqupgo/logger\"\n    \"github.com/quiqupltd/quiqupgo/temporal\"\n    \"github.com/quiqupltd/quiqupgo/tracing\"\n    \"go.uber.org/fx\"\n)\n\n// AppConfig is your application's configuration\ntype AppConfig struct {\n    ServiceName string\n    Environment string\n    OTLP        struct {\n        Endpoint string\n        Insecure bool\n    }\n    Temporal struct {\n        HostPort  string\n        Namespace string\n    }\n    DB *sql.DB\n}\n\nfunc main() {\n    fx.New(\n        // Provide app config\n        fx.Provide(newAppConfig),\n\n        // Adapt app config to module configs\n        fx.Provide(\n            fx.Annotate(newTracingConfig, fx.As(new(tracing.Config))),\n            fx.Annotate(newLoggerConfig, fx.As(new(logger.Config))),\n            fx.Annotate(newTemporalConfig, fx.As(new(temporal.Config))),\n            fx.Annotate(newGormConfig, fx.As(new(gormfx.Config))),\n        ),\n\n        // Include modules\n        tracing.Module(),\n        logger.Module(),\n        temporal.Module(),\n        gormfx.Module(),\n\n        // Your application code\n        fx.Invoke(run),\n    ).Run()\n}\n\nfunc newTracingConfig(app *AppConfig) tracing.Config {\n    return \u0026tracing.StandardConfig{\n        ServiceName:     app.ServiceName,\n        EnvironmentName: app.Environment,\n        OTLPEndpoint:    app.OTLP.Endpoint,\n        OTLPInsecure:    app.OTLP.Insecure,\n    }\n}\n\nfunc newLoggerConfig(app *AppConfig) logger.Config {\n    return \u0026logger.StandardConfig{\n        ServiceName: app.ServiceName,\n        Environment: app.Environment,\n    }\n}\n\nfunc newTemporalConfig(app *AppConfig) temporal.Config {\n    return \u0026temporal.StandardConfig{\n        HostPort:  app.Temporal.HostPort,\n        Namespace: app.Temporal.Namespace,\n    }\n}\n\nfunc newGormConfig(app *AppConfig) gormfx.Config {\n    return \u0026gormfx.StandardConfig{\n        DB: app.DB,\n    }\n}\n```\n\n## Module Details\n\n### Tracing Module\n\nProvides OpenTelemetry tracing and metrics infrastructure.\n\n```go\nimport \"github.com/quiqupltd/quiqupgo/tracing\"\n\n// What it provides via fx:\n// - trace.TracerProvider\n// - trace.Tracer\n// - metric.MeterProvider\n// - metric.Meter\n\n// Configuration interface\ntype Config interface {\n    GetServiceName() string\n    GetEnvironmentName() string\n    GetOTLPEndpoint() string\n    GetOTLPInsecure() bool\n    GetOTLPTLSCert() string   // base64 encoded\n    GetOTLPTLSKey() string    // base64 encoded\n    GetOTLPTLSCA() string     // base64 encoded\n}\n\n// Usage\nfx.New(\n    fx.Provide(func() tracing.Config {\n        return \u0026tracing.StandardConfig{\n            ServiceName:     \"my-service\",\n            EnvironmentName: \"production\",\n            OTLPEndpoint:    \"otel-collector:4318\",\n        }\n    }),\n    tracing.Module(\n        tracing.WithBatchTimeout(5 * time.Second),\n        tracing.WithSampler(sdktrace.AlwaysSample()),\n    ),\n)\n```\n\n### Logger Module\n\nProvides structured logging with zap and optional OpenTelemetry integration.\n\n```go\nimport \"github.com/quiqupltd/quiqupgo/logger\"\n\n// What it provides via fx:\n// - *zap.Logger\n// - logger.Logger (interface)\n\n// Configuration interface\ntype Config interface {\n    GetServiceName() string\n    GetEnvironment() string  // \"development\" for pretty logs, else JSON\n}\n\n// Usage\nfx.New(\n    fx.Provide(func() logger.Config {\n        return \u0026logger.StandardConfig{\n            ServiceName: \"my-service\",\n            Environment: \"development\",\n        }\n    }),\n    logger.Module(),\n)\n```\n\n### Temporal Module\n\nProvides Temporal workflow client with OTEL tracing.\n\n```go\nimport \"github.com/quiqupltd/quiqupgo/temporal\"\n\n// What it provides via fx:\n// - client.Client (Temporal client)\n\n// Configuration interface\ntype Config interface {\n    GetHostPort() string\n    GetNamespace() string\n    GetTLSCert() string  // PEM encoded\n    GetTLSKey() string   // PEM encoded\n}\n\n// Dependencies (must be provided):\n// - *zap.Logger\n// - trace.Tracer\n\n// Usage\nfx.New(\n    // ... logger and tracing modules first\n    fx.Provide(func() temporal.Config {\n        return \u0026temporal.StandardConfig{\n            HostPort:  \"localhost:7233\",\n            Namespace: \"default\",\n        }\n    }),\n    temporal.Module(),\n)\n```\n\n### GORM Module\n\nProvides GORM database connection with OTEL tracing plugin.\n\n```go\nimport \"github.com/quiqupltd/quiqupgo/gormfx\"\n\n// What it provides via fx:\n// - *gorm.DB\n\n// Configuration interface\ntype Config interface {\n    GetDB() *sql.DB\n}\n\n// Dependencies (must be provided):\n// - trace.TracerProvider\n\n// Usage\nfx.New(\n    // ... tracing module first\n    fx.Provide(func(db *sql.DB) gormfx.Config {\n        return \u0026gormfx.StandardConfig{DB: db}\n    }),\n    gormfx.Module(),\n)\n```\n\n### Kafka Module\n\nProvides Kafka producer and consumer with OTEL tracing.\n\n```go\nimport \"github.com/quiqupltd/quiqupgo/kafka\"\n\n// What it provides via fx:\n// - kafka.Producer\n// - kafka.Consumer\n\n// Configuration interface\ntype Config interface {\n    GetBrokers() []string\n    GetConsumerGroup() string\n    GetTopics() []string\n}\n\n// Dependencies (must be provided):\n// - trace.Tracer\n// - *zap.Logger\n\n// Usage\nfx.New(\n    // ... logger and tracing modules first\n    fx.Provide(func() kafka.Config {\n        return \u0026kafka.StandardConfig{\n            Brokers:       []string{\"kafka:9092\"},\n            ConsumerGroup: \"my-service\",\n            Topics:        []string{\"events\"},\n        }\n    }),\n    kafka.Module(),\n)\n```\n\n### Middleware Module\n\nProvides HTTP middleware for tracing (not an fx.Module - standalone functions).\n\n```go\nimport \"github.com/quiqupltd/quiqupgo/middleware\"\n\n// Echo middleware\ne := echo.New()\ne.Use(middleware.EchoTracing(tracerProvider, \"my-service\"))\n\n// Standard http middleware\nmux := http.NewServeMux()\nhandler := middleware.HTTPTracing(tracerProvider, \"my-service\")(mux)\n```\n\n### Encore Middleware\n\nProvides helpers for integrating OpenTelemetry tracing with [Encore.dev](https://encore.dev) applications.\n\n```go\nimport \"github.com/quiqupltd/quiqupgo/middleware/encore\"\n\n// In your Encore application, create middleware that wraps these helpers:\n\n//encore:middleware global target=all\nfunc TracingMiddleware(req middleware.Request, next middleware.Next) middleware.Response {\n    reqData := req.Data()\n    tp := getTracerProvider() // your tracer provider\n\n    ctx, span := encore.StartSpan(req.Context(), tp, \u0026encore.TraceInfo{\n        TraceID:       reqData.Trace.TraceID,\n        SpanID:        reqData.Trace.SpanID,\n        ParentTraceID: reqData.Trace.ParentTraceID,\n        ParentSpanID:  reqData.Trace.ParentSpanID,\n    }, reqData.Endpoint.Name,\n        trace.WithSpanKind(trace.SpanKindServer),\n    )\n    defer span.End()\n\n    resp := next(req.WithContext(ctx))\n    if resp.Err != nil {\n        span.RecordError(resp.Err)\n    }\n    return resp\n}\n```\n\n**Key Functions:**\n- `StartSpan()` - Creates OTEL spans correlated with Encore's trace context (recommended)\n- `StartSpanWithParent()` - Creates child spans under Encore's span (only if Encore exports to same backend)\n- `ConvertTraceID()` / `ConvertSpanID()` - Convert Encore's base32 IDs to OTEL format\n\n**Why `StartSpan` instead of `StartSpanWithParent`?**\n\nEncore exports its own traces separately. Using `StartSpanWithParent` would create child spans referencing a parent that may not exist in your tracing backend, causing \"root span not yet received\" errors. `StartSpan` creates correlated but independent root spans that share the same trace ID for correlation.\n\n## Testing\n\nEach module provides test utilities:\n\n```go\nimport (\n    loggertest \"github.com/quiqupltd/quiqupgo/logger/testutil\"\n    tracingtest \"github.com/quiqupltd/quiqupgo/tracing/testutil\"\n    temporaltest \"github.com/quiqupltd/quiqupgo/temporal/testutil\"\n)\n\nfunc TestMyService(t *testing.T) {\n    // Get buffer logger for assertions\n    logMod, buffer := loggertest.BufferModule()\n\n    var svc *MyService\n    app := fx.New(\n        fx.NopLogger,\n        tracingtest.NoopModule(),  // No-op tracing\n        logMod,                     // Buffer logger\n        temporaltest.MockModule(), // Mock temporal client\n        fx.Provide(NewMyService),\n        fx.Populate(\u0026svc),\n    )\n\n    ctx := context.Background()\n    require.NoError(t, app.Start(ctx))\n    defer app.Stop(ctx)\n\n    // Test your service\n    svc.DoSomething()\n\n    // Assert on logs\n    entries := buffer.GetEntries()\n    assert.Contains(t, entries[0].Message, \"did something\")\n}\n```\n\n## Creating Your Own App Module\n\nBest practice is to create your own composition module that adapts your app config:\n\n```go\n// internal/fxglobal/module.go\npackage fxglobal\n\nimport (\n    \"github.com/quiqupltd/quiqupgo/gormfx\"\n    \"github.com/quiqupltd/quiqupgo/logger\"\n    \"github.com/quiqupltd/quiqupgo/tracing\"\n    \"go.uber.org/fx\"\n)\n\nfunc Module(serviceName string, db *sql.DB) fx.Option {\n    return fx.Module(\"global\",\n        fx.Provide(func() *AppConfig {\n            return loadAppConfig()\n        }),\n\n        // Adapt to module configs\n        fx.Provide(\n            fx.Annotate(newTracingConfig, fx.As(new(tracing.Config))),\n            fx.Annotate(newLoggerConfig, fx.As(new(logger.Config))),\n            fx.Annotate(func() gormfx.Config {\n                return \u0026gormfx.StandardConfig{DB: db}\n            }, fx.As(new(gormfx.Config))),\n        ),\n\n        // Include modules (only what you need)\n        tracing.Module(),\n        logger.Module(),\n        gormfx.Module(),\n        // temporal.Module() - not needed for this service\n    )\n}\n```\n\n## Development\n\n### Prerequisites\n\n- Go 1.24+ (via asdf: `asdf install`)\n- [Task](https://taskfile.dev/) (via asdf: `asdf install`)\n- Docker or [OrbStack](https://orbstack.dev/)\n- [direnv](https://direnv.net/) (optional, for automatic environment loading)\n\n### Setup\n\n```bash\n# Install Go and Task via asdf\nasdf install\n\n# Install development tools\ntask tools:install\n\n# Setup git hooks\ntask tools:hooks\n\n# Run tests\ntask test:unit\n\n# Run linter\ntask tools:lint\n\n# Format code\ntask tools:fmt\n```\n\n### Running Integration Tests\n\nIntegration tests require local infrastructure (Redpanda, Postgres, Temporal, etc.):\n\n```bash\n# Start all services via OrbStack/Docker\ntask docker:up\n\n# Wait for services to be healthy\ntask docker:status\n\n# Run integration tests\ntask test:integration\n\n# Stop services when done\ntask docker:down\n```\n\nServices are accessible at:\n- Postgres: `localhost:5432`\n- Redpanda/Kafka: `localhost:19092`\n- Temporal: `localhost:7233`\n- Jaeger UI: `localhost:16686`\n- Redpanda Console: `localhost:8080`\n\n### Available Tasks\n\n```bash\ntask --list\n```\n\n## Versioning \u0026 Releases\n\nThis project uses [Semantic Versioning](https://semver.org/) and [Git Flow](https://nvie.com/posts/a-successful-git-branching-model/) for release management.\n\n### Consuming Specific Versions\n\n```bash\n# Latest version\ngo get github.com/quiqupltd/quiqupgo\n\n# Specific version\ngo get github.com/quiqupltd/quiqupgo@v0.1.0\n\n# Latest patch for a minor version\ngo get github.com/quiqupltd/quiqupgo@v0.1\n```\n\n### Branching Strategy\n\n| Branch | Purpose |\n|--------|---------|\n| `main` | Production-ready releases, tagged with versions |\n| `develop` | Integration branch for features |\n| `feat/*` | New features and enhancements |\n| `rel/*` | Release preparation |\n| `hotfix/*` | Critical production fixes |\n\n### Version History\n\nSee [CHANGELOG.md](CHANGELOG.md) for detailed release notes and [GitHub Releases](https://github.com/quiqupltd/quiqupgo/releases) for downloadable artifacts.\n\n## Project Structure\n\n```\nquiqupgo/\n├── tracing/          # OpenTelemetry tracing + metrics module\n├── logger/           # Structured logging module\n├── temporal/         # Temporal workflow client module\n├── gormfx/           # GORM database module\n├── kafka/           # Kafka messaging module\n├── middleware/       # HTTP middleware\n│   └── encore/       # Encore.dev tracing helpers\n├── fxutil/           # Shared utilities\n├── examples/         # Example applications\n│   ├── minimal/      # Logger only\n│   ├── api-service/  # Tracing + Logger + GORM\n│   └── worker-service/ # All modules\n└── docs/             # Documentation\n```\n\n## License\n\nMIT License - see LICENSE file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquiqupltd%2Fquiqupgo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquiqupltd%2Fquiqupgo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquiqupltd%2Fquiqupgo/lists"}