feat: Universal auto-instrumentation for all languages

## New Features

### Universal Instrumentation Container
- Created deploy/instrumentation/ with Dockerfile that downloads OTel agents for:
  - .NET (glibc and musl/Alpine versions)
  - Node.js (with auto-instrumentation package)
  - Python (bootstrap script + requirements)
  - Java (javaagent JAR)
  - Go (example code for compile-time instrumentation)
  - PHP (composer package + init script)

### Universal instrument.sh Script
- Auto-detects application language from running processes
- Generates docker-compose snippets for each language
- Supports: dotnet, nodejs, python, java, go, php
- Usage: ./instrument.sh <container> [language] [otlp_endpoint]

### Improved docker-compose.yml
- Added instrumentation init container with shared volume
- Added AGENT_KEY environment variable for proper auth
- Added ophion-agent service for host metrics collection
- Named containers for easier management
- Added ophion-network for service discovery

### Documentation
- Created docs/QUICK_START.md with:
  - Single-command installation
  - Instrumentation guide for all languages
  - Troubleshooting section
  - Authentication guide

### Auth Fixes
- Server now properly validates AGENT_KEY for agent authentication
- OTel Collector configured with AGENT_KEY for forwarding to server
- Fixed 401 errors when agents connect

## Files Changed
- docker-compose.yml: Complete stack with all services
- deploy/instrumentation/*: Universal OTel agent container
- deploy/docker/otel-collector-config.yaml: Fixed auth headers
- instrument.sh: Universal instrumentation script
- docs/QUICK_START.md: Complete quick start guide
- README.md: Updated with new features
- .env.example: Added AGENT_KEY

## Testing
- Go code compiles successfully
- Docker images build correctly
- All changes are backwards compatible
This commit is contained in:
2026-02-06 19:28:43 -03:00
parent 0cd8b96cd0
commit 6f9657a3a8
16 changed files with 1279 additions and 148 deletions

View File

@@ -1,6 +1,6 @@
# ═══════════════════════════════════════════════════════════
# 🐍 OPHION - OpenTelemetry Collector Configuration
# Receives traces/metrics/logs from instrumented applications
# Central collector for all instrumented applications
# ═══════════════════════════════════════════════════════════
receivers:
@@ -14,8 +14,10 @@ receivers:
cors:
allowed_origins:
- "*"
allowed_headers:
- "*"
# Prometheus receiver for metrics scraping (optional)
# Prometheus receiver for scraping metrics
prometheus:
config:
scrape_configs:
@@ -43,22 +45,24 @@ processors:
- key: collector.name
value: ophion-collector
action: upsert
- key: deployment.environment
from_attribute: OTEL_RESOURCE_ATTRIBUTES
action: upsert
# Attributes processor for enrichment
attributes:
actions:
- key: ophion.collected
value: true
action: upsert
# Transform processor for data enrichment
transform:
trace_statements:
- context: span
statements:
- set(attributes["ophion.collected"], true)
metric_statements:
- context: datapoint
statements:
- set(attributes["ophion.collected"], true)
exporters:
# Export to Ophion server via OTLP
otlphttp/ophion:
# Export traces to Ophion server via HTTP
otlphttp/traces:
endpoint: http://server:8080
headers:
Authorization: "Bearer ${env:AGENT_KEY}"
X-Ophion-Source: otel-collector
compression: gzip
retry_on_failure:
@@ -67,13 +71,29 @@ exporters:
max_interval: 30s
max_elapsed_time: 300s
# Debug exporter for troubleshooting (disable in production)
# Export metrics to Ophion server
otlphttp/metrics:
endpoint: http://server:8080
headers:
Authorization: "Bearer ${env:AGENT_KEY}"
X-Ophion-Source: otel-collector
compression: gzip
# Export logs to Ophion server
otlphttp/logs:
endpoint: http://server:8080
headers:
Authorization: "Bearer ${env:AGENT_KEY}"
X-Ophion-Source: otel-collector
compression: gzip
# Debug exporter for troubleshooting
debug:
verbosity: basic
sampling_initial: 5
sampling_thereafter: 200
# Prometheus exporter for collector metrics
# Prometheus exporter for collector's own metrics
prometheus:
endpoint: 0.0.0.0:8889
namespace: ophion_collector
@@ -99,20 +119,20 @@ service:
# Traces pipeline
traces:
receivers: [otlp]
processors: [memory_limiter, batch, resource, attributes]
exporters: [otlphttp/ophion, debug]
processors: [memory_limiter, batch, resource, transform]
exporters: [otlphttp/traces, debug]
# Metrics pipeline
# Metrics pipeline
metrics:
receivers: [otlp, prometheus]
processors: [memory_limiter, batch, resource]
exporters: [otlphttp/ophion, debug]
exporters: [otlphttp/metrics, debug]
# Logs pipeline
logs:
receivers: [otlp]
processors: [memory_limiter, batch, resource]
exporters: [otlphttp/ophion, debug]
exporters: [otlphttp/logs, debug]
telemetry:
logs:

View File

@@ -0,0 +1,74 @@
# ═══════════════════════════════════════════════════════════
# 🔧 OPHION Universal Instrumentation Container
# Downloads and provides OpenTelemetry agents for all languages
# ═══════════════════════════════════════════════════════════
FROM alpine:3.19
LABEL org.opencontainers.image.title="OPHION Instrumentation"
LABEL org.opencontainers.image.description="OpenTelemetry agents for .NET, Node.js, Python, Java, Go, PHP"
# Install tools
RUN apk add --no-cache curl unzip bash jq
# Create directory structure
RUN mkdir -p /otel/{dotnet,dotnet-musl,nodejs,python,java,go,php}
WORKDIR /otel
# ═══════════════════════════════════════════════════════════
# .NET Auto-Instrumentation (glibc)
# ═══════════════════════════════════════════════════════════
ENV OTEL_DOTNET_VERSION=1.6.0
RUN curl -L --retry 3 --retry-delay 5 --max-time 120 \
"https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/download/v${OTEL_DOTNET_VERSION}/opentelemetry-dotnet-instrumentation-linux-glibc-x64.zip" \
-o /tmp/dotnet.zip && \
unzip -q /tmp/dotnet.zip -d /otel/dotnet && \
rm /tmp/dotnet.zip && \
chmod +x /otel/dotnet/*.sh 2>/dev/null || true
# .NET Auto-Instrumentation (musl/Alpine)
RUN curl -L --retry 3 --retry-delay 5 --max-time 120 \
"https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/download/v${OTEL_DOTNET_VERSION}/opentelemetry-dotnet-instrumentation-linux-musl-x64.zip" \
-o /tmp/dotnet-musl.zip && \
unzip -q /tmp/dotnet-musl.zip -d /otel/dotnet-musl && \
rm /tmp/dotnet-musl.zip && \
chmod +x /otel/dotnet-musl/*.sh 2>/dev/null || true
# ═══════════════════════════════════════════════════════════
# Java Auto-Instrumentation
# Uses GitHub API to get proper redirect
# ═══════════════════════════════════════════════════════════
ENV OTEL_JAVA_VERSION=2.1.0
RUN JAVA_URL=$(curl -sL "https://api.github.com/repos/open-telemetry/opentelemetry-java-instrumentation/releases/tags/v${OTEL_JAVA_VERSION}" | \
jq -r '.assets[] | select(.name=="opentelemetry-javaagent.jar") | .browser_download_url') && \
if [ -n "$JAVA_URL" ] && [ "$JAVA_URL" != "null" ]; then \
curl -L --retry 3 --max-time 180 "$JAVA_URL" -o /otel/java/opentelemetry-javaagent.jar; \
else \
echo "Downloading Java agent directly..." && \
curl -L --retry 3 --max-time 180 \
"https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v${OTEL_JAVA_VERSION}/opentelemetry-javaagent.jar" \
-o /otel/java/opentelemetry-javaagent.jar; \
fi && \
ls -la /otel/java/
# ═══════════════════════════════════════════════════════════
# Copy pre-created files for other languages
# ═══════════════════════════════════════════════════════════
COPY files/ /otel/
# Set permissions
RUN chmod -R 755 /otel && \
chmod +x /otel/python/bootstrap.sh 2>/dev/null || true
# Verify downloads
RUN echo "=== OPHION Instrumentation Contents ===" && \
ls -la /otel/ && \
echo "=== Java agent size ===" && \
ls -lh /otel/java/opentelemetry-javaagent.jar 2>/dev/null || echo "Java agent not present" && \
echo "=== .NET ===" && ls /otel/dotnet/ | head -5
# Volume for sharing with other containers
VOLUME ["/otel"]
CMD ["echo", "OpenTelemetry agents ready in /otel"]

View File

@@ -0,0 +1,51 @@
# OPHION OpenTelemetry Agents
This volume contains auto-instrumentation agents for all major languages.
## Directory Structure
- `/otel/dotnet/` - .NET auto-instrumentation (glibc)
- `/otel/dotnet-musl/` - .NET auto-instrumentation (Alpine/musl)
- `/otel/nodejs/` - Node.js SDK and loader
- `/otel/python/` - Python requirements and bootstrap
- `/otel/java/` - Java agent JAR
- `/otel/go/` - Go instrumentation examples
- `/otel/php/` - PHP composer package
## Environment Variables (all languages)
- OTEL_EXPORTER_OTLP_ENDPOINT=http://ophion-otel-collector:4318
- OTEL_SERVICE_NAME=your-service-name
- OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production
## Usage Examples
### .NET
```dockerfile
ENV CORECLR_ENABLE_PROFILING=1
ENV CORECLR_PROFILER={918728DD-259F-4A6A-AC2B-B85E1B658571}
ENV CORECLR_PROFILER_PATH=/otel/dotnet/linux-x64/OpenTelemetry.AutoInstrumentation.Native.so
ENV DOTNET_ADDITIONAL_DEPS=/otel/dotnet/AdditionalDeps
ENV DOTNET_SHARED_STORE=/otel/dotnet/store
ENV DOTNET_STARTUP_HOOKS=/otel/dotnet/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll
ENV OTEL_DOTNET_AUTO_HOME=/otel/dotnet
```
### Node.js
```bash
node -r /otel/nodejs/instrument.js your-app.js
```
### Python
```bash
source /otel/python/bootstrap.sh
opentelemetry-instrument python your-app.py
```
### Java
```bash
java -javaagent:/otel/java/opentelemetry-javaagent.jar -jar your-app.jar
```
### PHP
```bash
cd your-app && composer require open-telemetry/sdk open-telemetry/exporter-otlp
```

View File

@@ -0,0 +1,5 @@
// Add these to your go.mod:
// go get go.opentelemetry.io/otel
// go get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
// go get go.opentelemetry.io/otel/sdk/trace
// go get go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp

View File

@@ -0,0 +1,34 @@
package main
import (
"context"
"os"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
)
func InitTracing(serviceName string) (*sdktrace.TracerProvider, error) {
ctx := context.Background()
exporter, err := otlptracehttp.New(ctx,
otlptracehttp.WithEndpoint(os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT")),
otlptracehttp.WithInsecure(),
)
if err != nil {
return nil, err
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(serviceName),
)),
)
otel.SetTracerProvider(tp)
return tp, nil
}

View File

@@ -0,0 +1,25 @@
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-http');
const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics');
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318';
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({
url: endpoint + '/v1/traces',
}),
metricReader: new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter({
url: endpoint + '/v1/metrics',
}),
exportIntervalMillis: 30000,
}),
instrumentations: [getNodeAutoInstrumentations()],
serviceName: process.env.OTEL_SERVICE_NAME || 'nodejs-app',
});
sdk.start();
process.on('SIGTERM', () => sdk.shutdown());
console.log('[OPHION] OpenTelemetry auto-instrumentation enabled');

View File

@@ -0,0 +1,11 @@
{
"name": "otel-nodejs-agent",
"version": "1.0.0",
"dependencies": {
"@opentelemetry/api": "^1.7.0",
"@opentelemetry/auto-instrumentations-node": "^0.43.0",
"@opentelemetry/sdk-node": "^0.48.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.48.0",
"@opentelemetry/exporter-metrics-otlp-http": "^0.48.0"
}
}

View File

@@ -0,0 +1,9 @@
{
"require": {
"open-telemetry/sdk": "^1.0",
"open-telemetry/exporter-otlp": "^1.0",
"open-telemetry/contrib-auto-slim": "^1.0",
"open-telemetry/contrib-auto-laravel": "^1.0",
"php-http/guzzle7-adapter": "^1.0"
}
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* OPHION PHP OpenTelemetry Initialization
* Include this file in your application bootstrap
*/
use OpenTelemetry\SDK\Sdk;
use OpenTelemetry\SDK\Trace\TracerProvider;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Common\Export\Http\PsrTransportFactory;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
$endpoint = getenv('OTEL_EXPORTER_OTLP_ENDPOINT') ?: 'http://localhost:4318';
$serviceName = getenv('OTEL_SERVICE_NAME') ?: 'php-app';
try {
$transport = (new PsrTransportFactory())->create($endpoint . '/v1/traces', 'application/json');
$exporter = new SpanExporter($transport);
$tracerProvider = TracerProvider::builder()
->addSpanProcessor(new SimpleSpanProcessor($exporter))
->setResource(ResourceInfo::create(Attributes::create(['service.name' => $serviceName])))
->build();
Sdk::builder()->setTracerProvider($tracerProvider)->buildAndRegisterGlobal();
error_log('[OPHION] OpenTelemetry initialized for PHP');
} catch (Exception $e) {
error_log('[OPHION] Failed to initialize OpenTelemetry: ' . $e->getMessage());
}

View File

@@ -0,0 +1,5 @@
#!/bin/bash
# OPHION Python Auto-Instrumentation Bootstrap
pip install -q -r /otel/python/requirements.txt
opentelemetry-bootstrap -a install 2>/dev/null || true
echo "[OPHION] Python OpenTelemetry packages installed"

View File

@@ -0,0 +1,3 @@
opentelemetry-distro>=0.43b0
opentelemetry-exporter-otlp>=1.22.0
opentelemetry-instrumentation>=0.43b0