# Building an OpenTelemetry Instrumentation Wizard

> Source: <https://dev.to/aairom/building-an-opentelemetry-instrumentation-wizard-1of5>
> Published: 2026-08-19 09:59:45+00:00

Accelerating observability adoption by automating OpenTelemetry instrumentation across heterogeneous codebases

Years ago, I was tasked with building OpenTelemetry metric collection for a client who wanted IBM Instana's capabilities without deploying the Instana agent to their production servers. Achieving that required meticulous, time-consuming effort to instrument their Go and Python applications manually. Recently, I faced almost the exact same challenge - except this time, I had Bob as an AI collaborator. Leveraging Bob, I set out to build an industrialized, universal instrumentation solution to solve the problem at scale.

Adding telemetry to existing applications is often tedious, manual, and error-prone. To solve this, we designed the OpenTelemetry (OTel) Instrumentation Wizard - a tool built with Streamlit and Python that automatically injects production-grade OTel traces, metrics, and logs across multiple programming languages while strictly preserving existing business logic. What follows is the implementation and the components.

The wizard operates as a structured multi-stage pipeline. Source files pass from initial language detection through AST/Regex analysis, safety validation, user review, and code injection before returning fully instrumented outputs.

`OTel-Wizard: injected`

] markers, guaranteeing zero disruption to original runtime logic.

```
otel-wizard/
├── app.py                     Streamlit UI (3-step wizard)
├── injectors/
│   ├── base_injector.py       Abstract base + InjectionResult dataclass
│   ├── python_injector.py     AST-aware Python injector
│   ├── go_injector.py         Go import + initTracer() injector
│   ├── java_injector.py       Java try-with-resources span injector
│   ├── javascript_injector.py Node.js SDK setup + span injector
│   ├── typescript_injector.py ES import syntax + typed Tracer injector
│   └── c_injector.py          C header + otel_start/end_span injector
├── utils/
│   ├── language_detector.py   Extension + heuristic language detection
│   └── diff_viewer.py         Unified text diff + colour-coded HTML diff
├── samples/                   Six hello-world files (pre-injection)
├── tests/                     pytest suite (8 test files, 128 assertions)
├── requirements.txt
├── .env.example
└── run_tests.sh
```

The wizard targets official OpenTelemetry semantic conventions across 7 key languages, applying tailored injection strategies according to each language's SDK maturity:

```
| Language                | Traces   | Metrics  | Logs     | Injection Strategy                                  |
| ----------------------- | -------- | -------- | -------- | --------------------------------------------------- |
| Python (Generic)        | ✅ Stable | ✅ Stable | ✅ Dev    | AST-based (`ast` module)                            |
| Python - Flask          | ✅ Stable | ✅ Stable | ✅ Dev    | AST + `FlaskInstrumentor` middleware                |
| Python - FastAPI        | ✅ Stable | ✅ Stable | ✅ Dev    | AST + `FastAPIInstrumentor` + ASGI hook             |
| Python - Django         | ✅ Stable | ✅ Stable | ✅ Dev    | AST + `DjangoInstrumentor` + `Psycopg2Instrumentor` |
| JavaScript / TypeScript | ✅ Stable | ✅ Stable | ⚠️ Dev    | Regex + template                                    |
| Go                      | ✅ Stable | ✅ Stable | ⚠️ Beta   | Regex + template                                    |
| Java                    | ✅ Stable | ✅ Stable | ✅ Stable | Template overlay                                    |
| C# / .NET               | ✅ Stable | ✅ Stable | ✅ Stable | ActivitySource template                             |
| Ruby                    | ✅ Stable | ⚠️ Dev    | ⚠️ Dev    | Regex + template                                    |
| PHP                     | ✅ Stable | ✅ Stable | ✅ Stable | Regex + template                                    |

> Signal status reflects the official [OpenTelemetry Language Status](https://opentelemetry.io/docs/languages/) as of 2025.
```

Python Supported Frameworks

Special Python based frameworks are also implemented in the wizard;

```
| Framework   | What Gets Injected                                           |
| ----------- | ------------------------------------------------------------ |
| **Generic** | SDK imports, `TracerProvider` init, span context managers around all functions |
| **Flask**   | All of the above + `FlaskInstrumentor().instrument_app(app, excluded_urls=...)` + `RequestsInstrumentor().instrument()` |
| **FastAPI** | All of the above + `FastAPIInstrumentor.instrument_app(app, excluded_urls=..., exclude_spans=["receive"])` + `HTTPXClientInstrumentor().instrument()` |
| **Django**  | All of the above + `DjangoInstrumentor().instrument(request_hook=..., is_sql_commentor_enabled=True)` + `Psycopg2Instrumentor().instrument()` - inserted **before** `get_wsgi_application()` / `get_asgi_application()` |
```

Framework-specific

`requirements.txt`

entries are also generated automatically.

Users retain full control over how telemetry is applied across their services through the wizard's configuration engine:

`service.name`

and s`ervice.version`

resource attributes dynamically.`otlp-http`

, `otlp-grpc`

, `console`

, and `prometheus`

endpoints.The architecture behind the OpenTelemetry Instrumentation Wizard follows a clean four-phase pipeline: **Detection → Analysis → Injection → Reporting**.

`wizard/core/models.py`

)

```
@dataclass
class WizardConfig:
    service_name: str = "my-service"
    service_version: str = "1.0.0"
    exporter: str = "otlp-http"
    otlp_endpoint: str = "http://localhost:4318"
    signals: list = field(default_factory=lambda: ["traces", "metrics", "logs"])
    depth: str = "medium"  # shallow | medium | deep
    sampling_ratio: float = 1.0

@dataclass
class InjectionPoint:
    signal: str          # "trace" | "metric" | "log"
    kind: str            # "span" | "counter" | "provider_init" ...
    location: str        # "function:<name>" | "file_top"
    reason: str
    code_preview: str
    enabled: bool = True
```

`wizard/core/detector.p`

y)

``` php
def detect_language(filename: str, source: str = "") -> dict:
    _, ext = os.path.splitext(filename.lower())
    if ext in EXTENSION_MAP:
        lang = EXTENSION_MAP[ext]
        return {"language": "javascript" if lang == "typescript" else lang, "confidence": "high"}

    if source:
        first_line = source.splitlines()[0] if source.splitlines() else ""
        if first_line.startswith("#!"):
            for pattern, lang in SHEBANG_PATTERNS:
                if re.search(pattern, first_line, re.IGNORECASE):
                    return {"language": lang, "confidence": "high"}
```

**- AST & Pattern Analysis ( wizard/core/analyzer.py)**

``` python
def generate_plan(source: str, language: str, filename: str, config: WizardConfig) -> InstrumentationPlan:
    plan = InstrumentationPlan(language=language, config=config)

    check = check_existing_instrumentation(source, language)
    if check["already_instrumented"]:
        plan.already_instrumented = True
        return plan

    plan.dependencies = _get_dependencies(language, config.signals)
    functions = _detect_functions(source, language, config.depth)

    for line_no, func_name, kind in functions:
        if "traces" in config.signals:
            plan.injection_points.append(InjectionPoint(
                signal="trace",
                kind="span",
                location=f"function:{func_name}",
                reason=f"Wrap '{func_name}' with a trace span for distributed tracing",
                code_preview=f"span '{func_name}' (line {line_no})"
            ))
    return plan
```

`wizard/core/injector.py`

)

``` php
def inject(source: str, plan: InstrumentationPlan, filename: str = "") -> InjectionResult:
    language = plan.language

    if language == "python":
        from wizard.languages.python_injector import PythonInjector
        injector = PythonInjector(plan)
    elif language == "javascript":
        from wizard.languages.js_injector import JSInjector
        injector = JSInjector(plan)
    # ... remaining target language dispatchers

    return injector.inject(source)
```

`wizard/app.py`

)
The main entry point ties the interactive user workflow together across four clear user steps:

`detect_language()`

.`generate_plan()`

to output an itemized data frame of target span hooks and missing dependencies.`inject()`

upon user confirmation.`generate_report()`

and packs the modified source, package metadata (`requirements.txt`

, `package.json`

, etc.), and markdown report into an in-memory ZIP archive.The core wizard module includes these language-specific injector implementations:

`wizard/core/injector.py`

) maps source languages to these concrete injector classes:

```
| Language                        | Injector Class       | Key Strategy & Tracing Mechanism                             |
| ------------------------------- | -------------------- | ------------------------------------------------------------ |
| **Python**  PY                  | `PythonInjector`  PY | Uses standard `ast` parsing to inject OTel imports, provider initializers, and wrap function bodies using `with _otel_tracer.start_as_current_span(...)` context managers.  PY |
| **JavaScript / TypeScript**  PY | `JSInjector`  PY     | Prepends tracer setup headers, generates an accompanying `instrumentation.js` file, and wraps functions with `_otelTracer.startActiveSpan(...)`.  PY |
| **Go**  PY                      | `GoInjector`  PY     | Injects `go.opentelemetry.io/otel` imports, adds an `initOtelProvider` initialization function, and inserts `ctx, _otelSpan := _otelTracer.Start(...)` with `defer _otelSpan.End()`.  PY |
| **Java**  PY                    | `JavaInjector`  PY   | Appends static `OpenTelemetry` class initializers and wraps public/protected method bodies using `try (Scope _ = ...)` and `finally { _otelSpan.end(); }` blocks.  PY |
| **C# / .NET**  PY               | `DotNetInjector`  PY | Injects native `System.Diagnostics.ActivitySource` fields and wraps methods using `using var _otelActivity = _otelSource.StartActivity(...)` with `try/catch` exception recording.  PY |
| **C**  PY                       | `CInjector`  PY      | Scans line-by-line using regex for C function signatures, injects `otel_init()` inside `main()`, and inserts macro/pointer span tracking blocks at function entry points.  PY |
| **PHP**  PY                     | `PHPInjector`  PY    | Prepends a PHP OTel bootstrap block and wraps function bodies in `startSpan()`, `activate()`, and `try/catch/finally` blocks.  PY |
| **Ruby**  PY                    | `RubyInjector`  PY   | Prepends `require 'opentelemetry/sdk'`, configures the global SDK, and wraps method bodies inside `_OTEL_TRACER.in_span(...) do ... end` blocks.  PY |
```

`// [OTel-Wizard: injected]`

(or `# [OTel-Wizard: injected])`

for easy auditing and tracing.`requirements.txt`

, `package.json`

, `go.mod`

, `pom.xml`

, `CMakeLists.txt`

, `Gemfile`

, or CLI package commands.In the **OTel Instrumentation Wizard**, injectors are specialized components responsible for parsing source code in a target programming language, inserting required OpenTelemetry SDK setup/imports, and wrapping key execution blocks (such as entry points or main functions) with span tracking logic.

**Base Abstraction & Lifecycle Control ( BaseInjector)**: Establishes a common

`inject(source_code, filename)`

contract and returns an `InjectionResult`

dataclass containing the modified source code, language metadata, and a human-readable list of changes. It provides shared helpers to enforce non-empty source checks (`_require_non_empty`

), detect pre-existing OTel instrumentation (`_already_has_otel`

), and scan for common entry points across languages (`_find_main_function`

). **Tracer Provider Initialisation**: Prepends or injects global tracer configuration, SDK setups, or SDK bootstrap calls suitable for the target runtime environment.

**Span Wrapping & Lifecycle Management**: Identifies entry functions (e.g., `main()`

, `if __name__ == "__main__":`

) and injects code to start spans at entry and guarantee proper span finalisation/teardown via native language constructs (such as `try-with-resources`

, `defer`

, `try/finally`

, or `with`

blocks).

**Idempotency Safeguards**: Checks for pre-existing OTel markers (e.g., `opentelemetry`

, `go.opentelemetry.io/otel`

) prior to modifying files, skipping injection if the source code is already instrumented.

`PythonInjector`

)
Inserts OTel imports, sets up a `TracerProvider`

and `ConsoleSpanExporter`

, and wraps the body of `def main():`

using Python's `with tracer.start_as_current_span(...)`

context manager while handling indentation.

Code Excerpt (`injectors/python_injector.py`

):

``` python
_OTEL_IMPORTS = """\
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
    BatchSpanProcessor,
    ConsoleSpanExporter,
)
from opentelemetry.sdk.resources import Resource, SERVICE_NAME
"""

_OTEL_PROVIDER_INIT = """\
# [OTel] Initialise TracerProvider
_otel_resource = Resource(attributes={SERVICE_NAME: __name__})
_otel_provider = TracerProvider(resource=_otel_resource)
_otel_provider.add_span_processor(
    BatchSpanProcessor(ConsoleSpanExporter())
)
trace.set_tracer_provider(_otel_provider)
tracer = trace.get_tracer(__name__)
"""
```

`GoInjector`

)
Injects `go.opentelemetry.io/otel`

packages into `import (...)`

blocks, appends an `initTracer()`

helper function, and modifies `func main()`

to initialize the provider with `defer tp.Shutdown(ctx)`

and defer span completion via `defer span.End()`

.

Code Excerpt (`injectors/go_injector.py`

):

```
_MAIN_PREAMBLE = """\
    // [OTel] Initialise tracer
    ctx := context.Background()
    tp, err := initTracer()
    if err != nil {
        log.Fatalf("failed to initialise tracer: %v", err)
    }
    defer func() {
        if shutdownErr := tp.Shutdown(ctx); shutdownErr != nil {
            log.Printf("tracer shutdown error: %v", shutdownErr)
        }
    }()
    tracer := otel.Tracer("main")
    ctx, span := tracer.Start(ctx, "main") // [OTel] root span
    defer span.End()
    _ = ctx // use ctx in downstream calls
"""
```

`JavaInjector`

)
Inserts `io.opentelemetry.api`

imports after package or existing import statements and wraps `public static void main(String[] args)`

with a `try-with-resources`

block using `Scope scope = span.makeCurrent()`

and explicit error reporting in a `catch`

block.

Code Excerpt (`injectors/java_injector.py`

):

```
otel_preamble = (
    f"\n{body_indent}// [OTel] Initialise tracer\n"
    f"{body_indent}OpenTelemetry openTelemetry = GlobalOpenTelemetry.get();\n"
    f"{body_indent}Tracer tracer = openTelemetry.getTracer(\"main\");\n"
    f"{body_indent}Span span = tracer.spanBuilder(\"main\").startSpan();\n"
    f"{body_indent}try (Scope scope = span.makeCurrent()) {{\n"
)
otel_postamble = (
    f"{body_indent}}} catch (Exception e) {{\n"
    f"{body_indent}    span.setStatus(StatusCode.ERROR, e.getMessage());\n"
    f"{body_indent}    throw e;\n"
    f"{body_indent}}} finally {{\n"
    f"{body_indent}    span.end();\n"
    f"{body_indent}}}\n"
)
```

`JavaScriptInjector`

/ `TypeScriptInjector`

)
Prepends a Node.js `NodeSDK`

configuration block and tracer acquisition (`_otelTracer.startSpan`

). TypeScript uses ES module imports and type declarations (`const _otelTracer: Tracer`

), wrapping function bodies with standard `try/catch/finally`

blocks.

Code Excerpt (`injectors/typescript_injector.py`

):

```
_OTEL_SETUP_BLOCK = """\
// [OTel] ── OpenTelemetry setup ──────────────────────────────────────────────
import { NodeSDK } from '@opentelemetry/sdk-node';
import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
import { trace, Tracer, context, SpanStatusCode } from '@opentelemetry/api';

const _otelSdk: NodeSDK = new NodeSDK({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'otel-wizard-service',
  }),
  traceExporter: new ConsoleSpanExporter(),
  instrumentations: [getNodeAutoInstrumentations()],
});
_otelSdk.start();
process.on('SIGTERM', (): void => { _otelSdk.shutdown(); });

const _otelTracer: Tracer = trace.getTracer('main');
// [OTel] ─────────────────────────────────────────────────────────────────────
"""
```

`CInjector`

)
Appends C OTel headers (`#include "opentelemetry_c/otel_api.h"`

), inserts `otel_init()`

and `otel_start_span("main")`

at the beginning of `int main()`

, injects `otel_end_span()`

prior to any `return`

statement inside `main()`

, and appends `otel_shutdown()`

before closing the function.

Code Excerpt (`injectors/c_injector.py`

):

```
_OTEL_MAIN_INIT = """\
    /* [OTel] Initialise tracer */
    otel_init("otel-wizard-service");
    otel_span_t *_otel_span = otel_start_span("main");
"""

_OTEL_MAIN_CLOSE = """\
    /* [OTel] End root span and shutdown */
    otel_end_span(_otel_span);
    otel_shutdown();
"""
```

The `utils`

directory provides critical supporting functionality for the OTel Instrumentation Wizard, focusing on file analysis and difference visualization:

**Language Detection ( utils/language_detector.py)**: The

`LanguageDetector`

class identifies programming languages through explicit extension maps and keyword content heuristics. It offers two primary mechanisms: `detect()`

, which strictly validates whether a file has an active injector available (raising `UnsupportedLanguageError`

otherwise), and `detect_any()`

, a non-raising alternative designed for fluid UI workflows that gracefully flags recognized but non-instrumentable languages. **Diff Generation & Visualisation ( utils/diff_viewer.py)**: Leverages Python's native

`difflib`

module to compute line-by-line differences between original and instrumented source code. It provides `generate_unified_diff()`

to output standard text diffs (`diff -u`

) and `generate_html_diff()`

to build sanitised, color-coded HTML views with styled line highlights (green for additions, red for deletions, and blue for hunk headers). To validate the code injection process across all supported target environments, the project includes clean, minimal "Hello World" benchmark samples free of any initial OpenTelemetry instrumentation:

**Language Coverage**: Standardized samples are provided for C (`helloworld.c`

), Go (`helloworld.go`

), Java (`HelloWorld.java`

), JavaScript (`helloworld.js`

), Python (`helloworld.py`

), and TypeScript (`helloworld.ts`

).

**Canonical Code Structure**: Each file implements a simple main entry point and helper greeting function (such as `greet()`

/ `main()`

). This standardized pattern allows unit and integration tests to reliably verify header/import additions, tracer setup placements, and entry-point span wrapping across every supported language.

```
  // tests/samples/go/sample_app.go
  // A plain Go HTTP server WITHOUT OTel instrumentation.
  // Used to validate the wizard's Go injection.

  package main

  import (
    "encoding/json"
    "fmt"
    "log"
    "math/rand"
    "net/http"
    "time"
  )

  type Item struct {
    Name     string  `json:"name"`
    Price    float64 `json:"price"`
    Quantity int     `json:"quantity"`
  }

  type OrderRequest struct {
    UserID int    `json:"user_id"`
    Items  []Item `json:"items"`
  }

  type OrderResponse struct {
    User   string  `json:"user"`
    Total  float64 `json:"total"`
    Status string  `json:"status"`
  }

  func calculateTotal(items []Item) float64 {
    total := 0.0
    for _, item := range items {
        qty := item.Quantity
        if qty == 0 {
            qty = 1
        }
        total += item.Price * float64(qty)
    }
    return total
  }

  func fetchUser(userID int) (map[string]interface{}, error) {
    time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond)
    if userID <= 0 {
        return nil, fmt.Errorf("invalid userID: %d", userID)
    }
    return map[string]interface{}{
        "id":   userID,
        "name": fmt.Sprintf("User_%d", userID),
    }, nil
  }

  func processOrder(userID int, items []Item) (*OrderResponse, error) {
    user, err := fetchUser(userID)
    if err != nil {
        return nil, err
    }
    total := calculateTotal(items)
    log.Printf("Order processed for %v: $%.2f", user["name"], total)
    return &OrderResponse{
        User:   user["name"].(string),
        Total:  total,
        Status: "confirmed",
    }, nil
  }

  func orderHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
        return
    }
    var req OrderRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    resp, err := processOrder(req.UserID, req.Items)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(resp)
  }

  func healthHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    fmt.Fprintf(w, `{"status":"ok"}`)
  }

  func main() {
    http.HandleFunc("/order", orderHandler)
    http.HandleFunc("/health", healthHandler)
    log.Println("Server listening on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
  }
```

**Step 4**: Download the modified Code

```
// tests/samples/go/sample_app.go
// A plain Go HTTP server WITHOUT OTel instrumentation.
// Used to validate the wizard's Go injection.

package main

import (
    "context"  // [OTel-Wizard: injected]
    "os"  // [OTel-Wizard: injected]
    "go.opentelemetry.io/otel"  // [OTel-Wizard: injected]
    "go.opentelemetry.io/otel/attribute"  // [OTel-Wizard: injected]
    "go.opentelemetry.io/otel/codes"  // [OTel-Wizard: injected]
    "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"  // [OTel-Wizard: injected]
    "go.opentelemetry.io/otel/sdk/resource"  // [OTel-Wizard: injected]
    sdktrace "go.opentelemetry.io/otel/sdk/trace"  // [OTel-Wizard: injected]
    semconv "go.opentelemetry.io/otel/semconv/v1.26.0"  // [OTel-Wizard: injected]
    "go.opentelemetry.io/otel/trace"  // [OTel-Wizard: injected]

// initOtelProvider initialises the TracerProvider. // [OTel-Wizard: injected]
func initOtelProvider(ctx context.Context) (func(context.Context) error, error) {
    exporter, err := otlptracehttp.New(ctx,
        otlptracehttp.WithEndpoint(getEnv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4318")),
        otlptracehttp.WithInsecure(),
    )
    if err != nil {
        return nil, err
    }
    res, err := resource.Merge(
        resource.Default(),
        resource.NewWithAttributes(
            semconv.SchemaURL,
            semconv.ServiceName(getEnv("OTEL_SERVICE_NAME", "my-service")),
            semconv.ServiceVersion(getEnv("OTEL_SERVICE_VERSION", "1.0.0")),
        ),
    )
    if err != nil {
        return nil, err
    }
    tp := sdktrace.NewTracerProvider(
        sdktrace.WithBatcher(exporter),
        sdktrace.WithResource(res),
    )
    otel.SetTracerProvider(tp)
    return tp.Shutdown, nil
}

// getEnv returns env var value or fallback. // [OTel-Wizard: injected]
func getEnv(key, fallback string) string {
    if v := os.Getenv(key); v != "" {
        return v
    }
    return fallback
}

var _otelTracer = otel.Tracer("my-service")  // [OTel-Wizard: injected]

    "encoding/json"
    "fmt"
    "log"
    "math/rand"
    "net/http"
    "time"
)

type Item struct {
    Name     string  `json:"name"`
    Price    float64 `json:"price"`
    Quantity int     `json:"quantity"`
}

type OrderRequest struct {
    UserID int    `json:"user_id"`
    Items  []Item `json:"items"`
}

type OrderResponse struct {
    User   string  `json:"user"`
    Total  float64 `json:"total"`
    Status string  `json:"status"`
}

func calculateTotal(items []Item) float64 {
    // [OTel-Wizard: injected]
    ctx, _otelSpan := _otelTracer.Start(ctx, "calculateTotal",
        trace.WithAttributes(attribute.String("code.function", "calculateTotal")))
    defer func() {
        if r := recover(); r != nil {
            _otelSpan.SetStatus(codes.Error, "panic")
            _otelSpan.End()
            panic(r)
        }
        _otelSpan.End()
    }()  // [OTel-Wizard: injected]
    _ = ctx  // [OTel-Wizard: injected]
    total := 0.0
    for _, item := range items {
        qty := item.Quantity
        if qty == 0 {
            qty = 1
        }
        total += item.Price * float64(qty)
    }
    return total
}

func fetchUser(userID int) (map[string]interface{}, error) {
    // [OTel-Wizard: injected]
    ctx, _otelSpan := _otelTracer.Start(ctx, "fetchUser",
        trace.WithAttributes(attribute.String("code.function", "fetchUser")))
    defer func() {
        if r := recover(); r != nil {
            _otelSpan.SetStatus(codes.Error, "panic")
            _otelSpan.End()
            panic(r)
        }
        _otelSpan.End()
    }()  // [OTel-Wizard: injected]
    _ = ctx  // [OTel-Wizard: injected]
    time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond)
    if userID <= 0 {
        return nil, fmt.Errorf("invalid userID: %d", userID)
    }
    return map[string]interface{}{
        "id":   userID,
        "name": fmt.Sprintf("User_%d", userID),
    }, nil
}

func processOrder(userID int, items []Item) (*OrderResponse, error) {
    // [OTel-Wizard: injected]
    ctx, _otelSpan := _otelTracer.Start(ctx, "processOrder",
        trace.WithAttributes(attribute.String("code.function", "processOrder")))
    defer func() {
        if r := recover(); r != nil {
            _otelSpan.SetStatus(codes.Error, "panic")
            _otelSpan.End()
            panic(r)
        }
        _otelSpan.End()
    }()  // [OTel-Wizard: injected]
    _ = ctx  // [OTel-Wizard: injected]
    user, err := fetchUser(userID)
    if err != nil {
        return nil, err
    }
    total := calculateTotal(items)
    log.Printf("Order processed for %v: $%.2f", user["name"], total)
    return &OrderResponse{
        User:   user["name"].(string),
        Total:  total,
        Status: "confirmed",
    }, nil
}

func orderHandler(w http.ResponseWriter, r *http.Request) {
    // [OTel-Wizard: injected]
    ctx, _otelSpan := _otelTracer.Start(ctx, "orderHandler",
        trace.WithAttributes(attribute.String("code.function", "orderHandler")))
    defer func() {
        if r := recover(); r != nil {
            _otelSpan.SetStatus(codes.Error, "panic")
            _otelSpan.End()
            panic(r)
        }
        _otelSpan.End()
    }()  // [OTel-Wizard: injected]
    _ = ctx  // [OTel-Wizard: injected]
    if r.Method != http.MethodPost {
        http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
        return
    }
    var req OrderRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    resp, err := processOrder(req.UserID, req.Items)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(resp)
}

func healthHandler(w http.ResponseWriter, r *http.Request) {
    // [OTel-Wizard: injected]
    ctx, _otelSpan := _otelTracer.Start(ctx, "healthHandler",
        trace.WithAttributes(attribute.String("code.function", "healthHandler")))
    defer func() {
        if r := recover(); r != nil {
            _otelSpan.SetStatus(codes.Error, "panic")
            _otelSpan.End()
            panic(r)
        }
        _otelSpan.End()
    }()  // [OTel-Wizard: injected]
    _ = ctx  // [OTel-Wizard: injected]
    w.Header().Set("Content-Type", "application/json")
    fmt.Fprintf(w, `{"status":"ok"}`)
}

func main() {
    http.HandleFunc("/order", orderHandler)
    http.HandleFunc("/health", healthHandler)
    log.Println("Server listening on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
```

… and the code’s dependencies;

```
# Add to go.mod require block:
go.opentelemetry.io/otel v1.33.0
go.opentelemetry.io/otel/sdk v1.33.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0
go.opentelemetry.io/otel/sdk/metric v1.33.0
```

The **OTel Instrumentation Wizard** provides an automated, end-to-end solution for introducing OpenTelemetry tracing into multi-language source code without requiring manual boilerplate construction. By leveraging a streamlined three-step workflow (**Upload → Preview Diff → Download**), the application abstracts the complexity of observability integration:

**Intelligent Language Detection & Flexibility**: Through the `LanguageDetector`

module, the wizard automatically identifies file types via explicit extension matching and keyword-based content heuristics. It provides broad recognition across many ecosystem languages while enforcing clear guardrails for supported injection targets.

**Robust Code Injection Engine**: Built upon a extensible `BaseInjector`

contract, concrete injectors for **Python**, **Go**, **Java**, **JavaScript**, **TypeScript**, and **C** automatically handle import injections, tracer provider setup, and entry-point span wrapping. Native language constructs (such as `try-with-resources`

, `defer`

, `with`

blocks, or explicit return-wrapping) guarantee safe span lifecycle management and error propagation across diverse runtime models.

**Safety, Transparency, & Idempotency**: Built-in safeguards check for pre-existing OTel markers to prevent duplicate instrumentation. The interactive UI offers full transparency via unified and color-coded HTML diff viewers (`utils/diff_viewer.py`

), ensuring developers can inspect and accept all injected modifications with total confidence.

**Empirically Validated Architecture**: Accompanied by standardized, clean test samples across all target languages, the architecture ensures reproducible and dependable AST/text transformations across real-world codebases.

Ultimately, the application bridges the gap between raw source code and modern observability practices, lowering the barrier to entry for distributed tracing across heterogeneous developer stacks.

**Thanks for reading 🔮**
