diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 582ed05..b7b6ab4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,42 +2,115 @@ name: CI on: push: - branches: [ "main" ] + branches: [ "main", "release/**" ] pull_request: - branches: [ "main" ] + branches: [ "main", "release/**" ] + +# Cancel any in-progress run for the same branch when a new push arrives. +# This avoids wasting runner minutes on stale commits. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + # Single source of truth for the linter version. + # Using v2.x to natively support Go 1.25/1.26 toolchains. + GOLANGCI_LINT_VERSION: v2.10.1 + +permissions: + contents: read jobs: + lint: + name: Lint & Hygiene + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }} + run: | + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh \ + | sh -s -- -b $(go env GOPATH)/bin ${{ env.GOLANGCI_LINT_VERSION }} + + - name: Verify module metadata is tidy + run: | + go mod tidy + git diff --exit-code go.mod go.sum || { + echo "::error::go.mod or go.sum is out of sync. Run 'go mod tidy' locally." + exit 1 + } + + - name: Format check + run: | + $(go env GOPATH)/bin/golangci-lint fmt --diff || { + echo "::error::Formatting issues found. Run 'golangci-lint fmt' locally." + exit 1 + } + + - name: Run golangci-lint + run: | + $(go env GOPATH)/bin/golangci-lint run --timeout=5m + test: + name: Test runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - go-version: [ "1.24", "1.25" ] - + go-version: [ "1.25", "1.26" ] + steps: - - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: ${{ matrix.go-version }} + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go-version }} + cache: true - - name: Install dependencies - run: go mod download + - name: Verify dependencies + run: go mod verify - - name: Verify dependencies - run: go mod verify + - name: Run Tests with Coverage + run: go test -v -race -coverprofile=coverage.txt -covermode=atomic ./... - - name: Run Tests - run: go test -v -race -cover ./... + - name: Upload coverage + uses: actions/upload-artifact@v4 + with: + name: coverage-report-${{ matrix.go-version }} + path: coverage.txt + retention-days: 5 - lint: + build: + name: Build (Cross-Compile) runs-on: ubuntu-latest + needs: [lint, test] + strategy: + fail-fast: false + matrix: + goos: [linux, darwin, windows] + goarch: [amd64, arm64] + steps: - - uses: actions/checkout@v4 - - uses: actions/setup-go@v4 - with: - go-version: '1.25' - - name: golangci-lint - uses: golangci/golangci-lint-action@v6 - with: - version: latest + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Verify compilation for ${{ matrix.goos }}/${{ matrix.goarch }} + env: + GOOS: ${{ matrix.goos }} + GOARCH: ${{ matrix.goarch }} + run: go build -v ./... diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..0a154d1 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,61 @@ +version: "2" + +# ── Run Options ───────────────────────────────────────────────────────────── +run: + timeout: 5m + tests: true # Re-enabling tests since this is a library and we want tests linted + + # Prevents golangci-lint from modifying go.mod when loading packages. + # Equivalent to running with -mod=readonly. Important in CI. + modules-download-mode: readonly + + # Resolve relative paths relative to the go.mod root. + # Produces cleaner, consistent output in CI and locally. + relative-path-mode: gomod + +# ── Linters ────────────────────────────────────────────────────────────────── +linters: + # Explicitly opt in to only the linters below. + # All others are disabled. Plug-and-play: uncomment a linter here + # and CI will enforce it on the next push — no changes to ci.yml needed. + default: none + + enable: + - govet # compiler-level checks (printf mismatches, unreachable code, etc.) + - ineffassign # detects assignments that are immediately overwritten + - unused # flags unused exported identifiers + - nolintlint # enforces correct usage of //nolint directives (no stale suppressions) + - staticcheck # full staticcheck suite (SA, ST, QF rules) + - errcheck # unhandled errors + - gosec # security analysis + + settings: + nolintlint: + # Require a reason to be provided with every //nolint directive. + require-explanation: true + # Disallow blanket //nolint with no specific linter named. + allow-no-explanation: [] + require-specific: true + +# ── Formatters ─────────────────────────────────────────────────────────────── +formatters: + # Driven by `golangci-lint fmt --diff` in CI. + # Adding a formatter here is the only change needed to enforce it everywhere. + disable-all: true + enable: + - gofmt + - goimports + + settings: + gofmt: + simplify: true + goimports: + local-prefixes: + - github.com/JupiterMetaLabs/ion + +# ── Issues ──────────────────────────────────────────────────────────────────── +issues: + # Show every violation — never hide duplicates or cap per-linter counts. + # Developers should see the full picture in one run, not whack-a-mole. + max-issues-per-linter: 0 + max-same-issues: 0 diff --git a/examples/basic/main.go b/examples/basic/main.go index 5464017..c530cbb 100644 --- a/examples/basic/main.go +++ b/examples/basic/main.go @@ -31,7 +31,7 @@ func example1_SimpleUsage() { for _, w := range warnings { log.Printf("ion warning: %v", w) } - defer app.Sync() + defer func() { _ = app.Sync() }() // Use Ion directly for logging app.Info(ctx, "application started") @@ -51,7 +51,7 @@ func example2_DependencyInjection() { if err != nil { log.Fatalf("Failed to create ion: %v", err) } - defer app.Sync() + defer func() { _ = app.Sync() }() // Pass a scoped child to components — preserves logging, tracing, and metrics server := NewServer(app.Child("server")) @@ -119,7 +119,7 @@ func example4_Metrics() { if err != nil { log.Fatalf("Failed to create ion: %v", err) } - defer app.Shutdown(ctx) + defer func() { _ = app.Shutdown(ctx) }() // Get a named meter meter := app.Meter("example.metrics") diff --git a/examples/benchmark/main.go b/examples/benchmark/main.go index b502c44..9a0db7d 100644 --- a/examples/benchmark/main.go +++ b/examples/benchmark/main.go @@ -16,10 +16,11 @@ import ( "testing" "time" - "github.com/JupiterMetaLabs/ion" - "github.com/JupiterMetaLabs/ion/fields" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/trace/noop" + + "github.com/JupiterMetaLabs/ion" + "github.com/JupiterMetaLabs/ion/fields" ) func main() { diff --git a/go.mod b/go.mod index 90bd590..111ec27 100644 --- a/go.mod +++ b/go.mod @@ -1,26 +1,26 @@ module github.com/JupiterMetaLabs/ion -go 1.24.0 +go 1.25.0 require ( - go.opentelemetry.io/contrib/bridges/otelzap v0.14.0 - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 - go.opentelemetry.io/otel v1.39.0 - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 - go.opentelemetry.io/otel/log v0.15.0 - go.opentelemetry.io/otel/metric v1.39.0 - go.opentelemetry.io/otel/sdk v1.39.0 - go.opentelemetry.io/otel/sdk/log v0.15.0 - go.opentelemetry.io/otel/sdk/metric v1.39.0 - go.opentelemetry.io/otel/trace v1.39.0 + go.opentelemetry.io/contrib/bridges/otelzap v0.17.0 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 + go.opentelemetry.io/otel v1.42.0 + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0 + go.opentelemetry.io/otel/log v0.18.0 + go.opentelemetry.io/otel/metric v1.42.0 + go.opentelemetry.io/otel/sdk v1.42.0 + go.opentelemetry.io/otel/sdk/log v0.18.0 + go.opentelemetry.io/otel/sdk/metric v1.42.0 + go.opentelemetry.io/otel/trace v1.42.0 go.uber.org/zap v1.27.1 - google.golang.org/grpc v1.77.0 + google.golang.org/grpc v1.79.3 gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) @@ -31,15 +31,15 @@ require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect - go.opentelemetry.io/proto/otlp v1.9.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.31.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect - google.golang.org/protobuf v1.36.10 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/sys v0.42.0 // indirect + golang.org/x/text v0.35.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7 // indirect + google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/go.sum b/go.sum index e3921ab..33dabd0 100644 --- a/go.sum +++ b/go.sum @@ -17,76 +17,76 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/bridges/otelzap v0.14.0 h1:2nKw2ZXZOC0N8RBsBbYwGwfKR7kJWzzyCZ6QfUGW/es= -go.opentelemetry.io/contrib/bridges/otelzap v0.14.0/go.mod h1:kvyVt0WEI5BB6XaIStXPIkCSQ2nSkyd8IZnAHLEXge4= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= -go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= -go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 h1:W+m0g+/6v3pa5PgVf2xoFMi5YtNR06WtS7ve5pcvLtM= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0/go.mod h1:JM31r0GGZ/GU94mX8hN4D8v6e40aFlUECSQ48HaLgHM= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0 h1:EKpiGphOYq3CYnIe2eX9ftUkyU+Y8Dtte8OaWyHJ4+I= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0/go.mod h1:nWFP7C+T8TygkTjJ7mAyEaFaE7wNfms3nV/vexZ6qt0= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 h1:cEf8jF6WbuGQWUVcqgyWtTR0kOOAWY1DYZ+UhvdmQPw= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0/go.mod h1:k1lzV5n5U3HkGvTCJHraTAGJ7MqsgL1wrGwTj1Isfiw= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0 h1:nKP4Z2ejtHn3yShBb+2KawiXgpn8In5cT7aO2wXuOTE= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0/go.mod h1:NwjeBbNigsO4Aj9WgM0C+cKIrxsZUaRmZUO7A8I7u8o= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= -go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypkyDY= -go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4= -go.opentelemetry.io/otel/log/logtest v0.15.0 h1:porNFuxAjodl6LhePevOc3n7bo3Wi3JhGXNWe7KP8iU= -go.opentelemetry.io/otel/log/logtest v0.15.0/go.mod h1:c8epqBXGHgS1LiNgmD+LuNYK9lSS3mqvtMdxLsfJgLg= -go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= -go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= -go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= -go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= -go.opentelemetry.io/otel/sdk/log v0.15.0 h1:WgMEHOUt5gjJE93yqfqJOkRflApNif84kxoHWS9VVHE= -go.opentelemetry.io/otel/sdk/log v0.15.0/go.mod h1:qDC/FlKQCXfH5hokGsNg9aUBGMJQsrUyeOiW5u+dKBQ= -go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= -go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= -go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= -go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= -go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= -go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= -go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= -go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= +go.opentelemetry.io/contrib/bridges/otelzap v0.17.0 h1:oCltVHJcblcth2z9B9dRTeZIZTe2Sf9Ad9h8bcc+s8M= +go.opentelemetry.io/contrib/bridges/otelzap v0.17.0/go.mod h1:G/VE1A/hRn6mEWdfC8rMvSdQVGM64KUPi4XilLkwcQw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0 h1:yI1/OhfEPy7J9eoa6Sj051C7n5dvpj0QX8g4sRchg04= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.67.0/go.mod h1:NoUCKYWK+3ecatC4HjkRktREheMeEtrXoQxrqYFeHSc= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg= +go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= +go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 h1:deI9UQMoGFgrg5iLPgzueqFPHevDl+28YKfSpPTI6rY= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0/go.mod h1:PFx9NgpNUKXdf7J4Q3agRxMs3Y07QhTCVipKmLsMKnU= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0 h1:icqq3Z34UrEFk2u+HMhTtRsvo7Ues+eiJVjaJt62njs= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0/go.mod h1:W2m8P+d5Wn5kipj4/xmbt9uMqezEKfBjzVJadfABSBE= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 h1:MdKucPl/HbzckWWEisiNqMPhRrAOQX8r4jTuGr636gk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0/go.mod h1:RolT8tWtfHcjajEH5wFIZ4Dgh5jpPdFXYV9pTAk/qjc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0 h1:H7O6RlGOMTizyl3R08Kn5pdM06bnH8oscSj7o11tmLA= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0/go.mod h1:mBFWu/WOVDkWWsR7Tx7h6EpQB8wsv7P0Yrh0Pb7othc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0/go.mod h1:2qXPNBX1OVRC0IwOnfo1ljoid+RD0QK3443EaqVlsOU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0 h1:uLXP+3mghfMf7XmV4PkGfFhFKuNWoCvvx5wP/wOXo0o= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0/go.mod h1:v0Tj04armyT59mnURNUJf7RCKcKzq+lgJs6QSjHjaTc= +go.opentelemetry.io/otel/log v0.18.0 h1:XgeQIIBjZZrliksMEbcwMZefoOSMI1hdjiLEiiB0bAg= +go.opentelemetry.io/otel/log v0.18.0/go.mod h1:KEV1kad0NofR3ycsiDH4Yjcoj0+8206I6Ox2QYFSNgI= +go.opentelemetry.io/otel/log/logtest v0.18.0 h1:2QeyoKJdIgK2LJhG1yn78o/zmpXx1EditeyRDREqVS8= +go.opentelemetry.io/otel/log/logtest v0.18.0/go.mod h1:v1vh3PYR9zIa5MK6HwkH2lMrLBg/Y9Of6Qc+krlesX0= +go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4= +go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI= +go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= +go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= +go.opentelemetry.io/otel/sdk/log v0.18.0 h1:n8OyZr7t7otkeTnPTbDNom6rW16TBYGtvyy2Gk6buQw= +go.opentelemetry.io/otel/sdk/log v0.18.0/go.mod h1:C0+wxkTwKpOCZLrlJ3pewPiiQwpzycPI/u6W0Z9fuYk= +go.opentelemetry.io/otel/sdk/log/logtest v0.18.0 h1:l3mYuPsuBx6UKE47BVcPrZoZ0q/KER57vbj2qkgDLXA= +go.opentelemetry.io/otel/sdk/log/logtest v0.18.0/go.mod h1:7cHtiVJpZebB3wybTa4NG+FUo5NPe3PROz1FqB0+qdw= +go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA= +go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc= +go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= +go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls= -google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= -google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= -google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 h1:41r6JMbpzBMen0R/4TZeeAmGXSJC7DftGINUodzTkPI= +google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:EIQZ5bFCfRQDV4MhRle7+OgjNtZ6P1PiZBgAKuxXu/Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7 h1:ndE4FoJqsIceKP2oYSnUZqhTdYufCYYkqwtFzfrhI7w= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/config/config.go b/internal/config/config.go index 2883c01..80c6049 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -120,7 +120,7 @@ type OTELConfig struct { Username string `yaml:"username" json:"username" env:"OTEL_USERNAME"` // Password for Basic Authentication (optional). - Password string `yaml:"password" json:"password" env:"OTEL_PASSWORD"` + Password string `yaml:"password" json:"password" env:"OTEL_PASSWORD"` //nolint:gosec // Required for configuration binding // Headers are additional headers to send (e.g., auth tokens). Headers map[string]string `yaml:"headers" json:"headers"` @@ -165,7 +165,7 @@ type TracingConfig struct { Username string `yaml:"username" json:"username" env:"TRACING_USERNAME"` // Password for Basic Authentication (optional). - Password string `yaml:"password" json:"password" env:"TRACING_PASSWORD"` + Password string `yaml:"password" json:"password" env:"TRACING_PASSWORD"` //nolint:gosec // Required for configuration binding // Headers for authentication. Headers map[string]string `yaml:"headers" json:"headers"` @@ -208,7 +208,7 @@ type MetricsConfig struct { Username string `yaml:"username" json:"username" env:"METRICS_USERNAME"` // Password for Basic Authentication (optional). - Password string `yaml:"password" json:"password" env:"METRICS_PASSWORD"` + Password string `yaml:"password" json:"password" env:"METRICS_PASSWORD"` //nolint:gosec // Required for configuration binding // Headers for authentication. Headers map[string]string `yaml:"headers" json:"headers"` diff --git a/internal/core/logger_factory.go b/internal/core/logger_factory.go index 90e6db6..6406b7b 100644 --- a/internal/core/logger_factory.go +++ b/internal/core/logger_factory.go @@ -5,10 +5,11 @@ import ( "os" "strings" - "github.com/JupiterMetaLabs/ion/internal/config" "go.opentelemetry.io/contrib/bridges/otelzap" "go.uber.org/zap" "go.uber.org/zap/zapcore" + + "github.com/JupiterMetaLabs/ion/internal/config" ) // ZapFactoryResult holds the result of constructing the zap logger. diff --git a/internal/core/meter.go b/internal/core/meter.go index a91149c..46321ba 100644 --- a/internal/core/meter.go +++ b/internal/core/meter.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - "github.com/JupiterMetaLabs/ion/internal/config" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" @@ -16,6 +15,8 @@ import ( semconv "go.opentelemetry.io/otel/semconv/v1.24.0" "google.golang.org/grpc" insecurecreds "google.golang.org/grpc/credentials/insecure" + + "github.com/JupiterMetaLabs/ion/internal/config" ) // MeterProvider wraps the OTEL MeterProvider. diff --git a/internal/core/otel.go b/internal/core/otel.go index de7cc5e..750b21b 100644 --- a/internal/core/otel.go +++ b/internal/core/otel.go @@ -9,7 +9,6 @@ import ( "strings" "time" - "github.com/JupiterMetaLabs/ion/internal/config" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc" @@ -24,6 +23,8 @@ import ( semconv "go.opentelemetry.io/otel/semconv/v1.32.0" "google.golang.org/grpc" insecurecreds "google.golang.org/grpc/credentials/insecure" + + "github.com/JupiterMetaLabs/ion/internal/config" ) // LogProvider manages the OpenTelemetry log provider. diff --git a/ion.go b/ion.go index e60f55d..d720e9c 100644 --- a/ion.go +++ b/ion.go @@ -5,9 +5,10 @@ import ( "fmt" "log" - "github.com/JupiterMetaLabs/ion/internal/core" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/noop" + + "github.com/JupiterMetaLabs/ion/internal/core" ) // Compile-time interface compliance check. @@ -49,7 +50,7 @@ var _ Logger = (*Ion)(nil) // counter.Add(ctx, 1) type Ion struct { *zapLogger // Embedded: promotes Debug, Info, Warn, Error, Critical, Sync, SetLevel, GetLevel. - // Caller depth is unified: all log calls are 1 frame above zap, matching AddCallerSkip(1). + // Caller depth is unified: all log calls are 1 frame above zap, matching AddCallerSkip(1). serviceName string version string tracerProvider *core.TracerProvider @@ -206,7 +207,7 @@ func New(cfg Config) (*Ion, []Warning, error) { // To get the *Ion directly without a type assertion, use [Ion.Child] instead. func (i *Ion) Named(name string) Logger { return &Ion{ - zapLogger: i.zapLogger.namedInternal(name), + zapLogger: i.namedInternal(name), serviceName: i.serviceName, version: i.version, tracerProvider: i.tracerProvider, @@ -225,7 +226,7 @@ func (i *Ion) Named(name string) Logger { // To get the *Ion directly without a type assertion, use [Ion.Child] instead. func (i *Ion) With(fields ...Field) Logger { return &Ion{ - zapLogger: i.zapLogger.withInternal(fields...), + zapLogger: i.withInternal(fields...), serviceName: i.serviceName, version: i.version, tracerProvider: i.tracerProvider, @@ -251,7 +252,7 @@ func (i *Ion) With(fields ...Field) Logger { // on a child will shut down shared providers, affecting the parent and all siblings. // In most applications, only the root Ion instance should be shut down. func (i *Ion) Child(name string, fields ...Field) *Ion { - child := i.zapLogger.namedInternal(name) + child := i.namedInternal(name) if len(fields) > 0 { child = child.withInternal(fields...) } diff --git a/ion_test.go b/ion_test.go index 97737dd..529b84a 100644 --- a/ion_test.go +++ b/ion_test.go @@ -44,7 +44,7 @@ func TestIon_Tracer(t *testing.T) { } // Create a span (no-op but should not panic) - //nolint:ineffassign // ctx update is standard tracing pattern, even if unused here + ctx, span := tracer.Start(ctx, "TestOperation") if span == nil { t.Fatal("expected non-nil span") @@ -295,17 +295,11 @@ func TestIon_SetLevelPropagation(t *testing.T) { // that *Ion satisfies Logger. func TestIon_InterfaceCompliance(t *testing.T) { app, _, _ := New(Default()) - - // Compile-time: this assignment must work - var l Logger = app - if l == nil { - t.Fatal("*Ion should satisfy Logger") - } + var _ Logger = app // compile-time check // Runtime: Named() result should also satisfy Logger - child := l.Named("test") - var l2 Logger = child - if l2 == nil { - t.Fatal("Named() result should satisfy Logger") + child := app.Named("test") + if child == nil { + t.Fatal("Named() result should satisfy Logger interface") } } diff --git a/logger_impl.go b/logger_impl.go index e665e01..4f3c345 100644 --- a/logger_impl.go +++ b/logger_impl.go @@ -5,9 +5,10 @@ import ( "errors" "fmt" - "github.com/JupiterMetaLabs/ion/internal/core" "go.uber.org/zap" "go.uber.org/zap/zapcore" + + "github.com/JupiterMetaLabs/ion/internal/core" ) // zapLogger implements Logger using Uber's Zap. diff --git a/middleware/iongrpc/grpc.go b/middleware/iongrpc/grpc.go index b3b1988..8b34c4e 100644 --- a/middleware/iongrpc/grpc.go +++ b/middleware/iongrpc/grpc.go @@ -34,7 +34,7 @@ func ServerHandler(opts ...Option) stats.Handler { otelOpts := []otelgrpc.Option{} if o.filter != nil { - otelOpts = append(otelOpts, otelgrpc.WithInterceptorFilter(o.filter)) //nolint:staticcheck // Supporting legacy filter for now + otelOpts = append(otelOpts, otelgrpc.WithInterceptorFilter(o.filter)) //nolint:staticcheck // OpenTelemetry backward compatibility // Supporting legacy filter for now } return otelgrpc.NewServerHandler(otelOpts...) @@ -56,7 +56,7 @@ func ClientHandler(opts ...Option) stats.Handler { otelOpts := []otelgrpc.Option{} if o.filter != nil { - otelOpts = append(otelOpts, otelgrpc.WithInterceptorFilter(o.filter)) //nolint:staticcheck // Supporting legacy filter for now + otelOpts = append(otelOpts, otelgrpc.WithInterceptorFilter(o.filter)) //nolint:staticcheck // OpenTelemetry backward compatibility // Supporting legacy filter for now } return otelgrpc.NewClientHandler(otelOpts...) @@ -65,7 +65,7 @@ func ClientHandler(opts ...Option) stats.Handler { // --- Options --- type options struct { - filter otelgrpc.InterceptorFilter //nolint:staticcheck + filter otelgrpc.InterceptorFilter //nolint:staticcheck // OpenTelemetry backward compatibility } func defaultOptions() *options { @@ -78,7 +78,7 @@ type Option interface { } type filterOption struct { - filter otelgrpc.InterceptorFilter //nolint:staticcheck + filter otelgrpc.InterceptorFilter //nolint:staticcheck // OpenTelemetry backward compatibility } func (f filterOption) apply(o *options) { o.filter = f.filter } @@ -91,6 +91,6 @@ func (f filterOption) apply(o *options) { o.filter = f.filter } // iongrpc.ServerHandler(iongrpc.WithFilter(func(info *otelgrpc.InterceptorInfo) bool { // return info.Method != "/grpc.health.v1.Health/Check" // })) -func WithFilter(filter otelgrpc.InterceptorFilter) Option { //nolint:staticcheck +func WithFilter(filter otelgrpc.InterceptorFilter) Option { //nolint:staticcheck // OpenTelemetry backward compatibility return filterOption{filter: filter} } diff --git a/middleware/ionhttp/http_test.go b/middleware/ionhttp/http_test.go index adf0606..be2476c 100644 --- a/middleware/ionhttp/http_test.go +++ b/middleware/ionhttp/http_test.go @@ -71,7 +71,7 @@ func TestClient(t *testing.T) { if err != nil { t.Fatalf("request failed: %v", err) } - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() if resp.StatusCode != http.StatusOK { t.Errorf("expected status 200, got %d", resp.StatusCode) @@ -93,7 +93,7 @@ func TestTransport(t *testing.T) { if err != nil { t.Fatalf("request failed: %v", err) } - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() if resp.StatusCode != http.StatusOK { t.Errorf("expected status 200, got %d", resp.StatusCode)