Skip to content

P2: OpenTelemetry integration — trace SQL parsing in distributed systems #451

@ajitpratap0

Description

@ajitpratap0

Problem

GoSQLX has no observability integration. In production microservices, teams need to trace SQL parsing duration, statement complexity, and dialect distribution alongside their application traces. Currently, GoSQLX is a black box from an observability perspective.

Proposed API

import (
    "go.opentelemetry.io/otel"
    "github.com/ajitpratap0/GoSQLX/pkg/integration/otel"
)

// Option 1: Wrap the gosqlx package with tracing
tracer := otel.Tracer("gosqlx")
tracedGosqlx := gosqlxotel.New(tracer)

ast, err := tracedGosqlx.Parse(ctx, sql)
// Emits span: gosqlx.parse
// Span attributes:
//   gosqlx.dialect = "postgresql"
//   gosqlx.statement_count = 1
//   gosqlx.statement_type = "select"
//   gosqlx.has_subquery = true
//   gosqlx.token_count = 47
//   gosqlx.parse_duration_ms = 0.12

// Option 2: ParseOptions with tracer injection (no wrapper needed)
ast, err := gosqlx.ParseWithOptions(sql, gosqlx.ParseOptions{
    Tracer: otel.Tracer("gosqlx"),
    Context: ctx,
})

Span Attributes to Emit

gosqlx.dialect           (string) — postgresql, mysql, etc.
gosqlx.statement_type    (string) — select, insert, update, delete, merge, etc.
gosqlx.statement_count   (int)    — for ParseMultiple
gosqlx.token_count       (int)    — tokenizer output size
gosqlx.has_subquery      (bool)   — complexity signal
gosqlx.has_cte           (bool)   — complexity signal
gosqlx.has_window        (bool)   — complexity signal
gosqlx.table_count       (int)    — number of tables referenced
gosqlx.complexity_score  (int)    — advisor complexity rating
gosqlx.error             (string) — parse error if any

Package Structure

pkg/integration/
├── otel/
│   ├── tracer.go          — TracedParser wrapper
│   ├── attributes.go      — Span attribute extraction from AST
│   └── tracer_test.go     — Unit tests with in-memory tracer
└── gorm/
    └── hooks.go           — GORM pre-query hook (separate issue)

Design Principles

  • Optional dependency: OTel packages are NOT in the main go.mod. The pkg/integration/otel sub-package adds its own go.mod with OTel as a dependency. Zero overhead if not used.
  • Context propagation: All traced calls require a context.Context; trace context is extracted automatically
  • No instrumentation overhead when disabled: Zero allocation path when no tracer is configured

Acceptance Criteria

  • pkg/integration/otel package with TracedParser wrapper
  • Span attributes cover: dialect, statement type, token count, complexity signals
  • OTel dependency in sub-module (not in main go.mod)
  • Tests using in-memory span exporter
  • Example in examples/otel-tracing/
  • Benchmark: zero overhead when tracer not configured (<1ns)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium priorityenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions