Signoz OTEL Collector Configuration Fix
Problem
The Signoz OTEL collector was failing to start with this error:
failed to start collector service: failed to start : failed to get config:
cannot resolve the configuration: invalid uri: "DEPLOYMENT_ENVIRONMENT:development"
Root Cause
The Signoz OTEL collector does not support environment variable substitution in YAML configuration files using the ${VAR:default} syntax. When it encountered:
resource:
attributes:
- key: deployment.environment
value: ${DEPLOYMENT_ENVIRONMENT:development}
It tried to use the literal string "DEPLOYMENT_ENVIRONMENT:development" as a value, which caused the configuration error.
Solution
Option 1: Use Hardcoded Value (Current Fix)
Changed the resource processor to use a hardcoded value:
resource:
attributes:
- key: deployment.environment
value: development # Hardcoded for now
action: upsert
Note: The deployment environment is actually set by each service's OpenTelemetry SDK initialization (in libs/observability/src/tracing/tracing.ts), so this collector-level setting is redundant anyway.
Option 2: Remove Resource Processor (Alternative)
If you don't need the resource processor, you can remove it entirely:
processors:
batch:
timeout: 1s
send_batch_size: 1024
memory_limiter:
limit_mib: 512
check_interval: 1s
# Resource processor removed - environment set by services
And update the pipelines:
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch] # Removed 'resource'
exporters: [clickhousetraces]
Why This Works
- Services set environment: Each service (api-gateway, booking-service, etc.) sets the deployment environment when initializing OpenTelemetry:
typescript
resource: new Resource({
[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env['NODE_ENV'] || 'development',
});
-
Collector doesn't need it: The collector just forwards traces/metrics/logs. The environment attribute is already set by the services.
-
Hardcoded is fine: For development, hardcoding
developmentis acceptable. For production, you can: - Use different config files per environment
- Or rely on services to set the correct environment
Changes Made
- Fixed
otel-collector-config.yaml: - Changed
${DEPLOYMENT_ENVIRONMENT:development}→development -
Added comment explaining why
-
Updated
docker-compose.dev.yml: - Added
DEPLOYMENT_ENVIRONMENTenvironment variable to collector container - This is for reference, not used by the config
Verification
After the fix, restart the collector:
docker compose -f docker-compose.dev.yml restart signoz-otel-collector
Check logs:
docker logs signoz-otel-collector
Should see:
{"level":"info","msg":"Starting collector service"}
{"level":"info","msg":"Everything is ready. Begin running and processing data."}
Production Considerations
For production, you have a few options:
Option 1: Separate Config Files
config/
├── signoz/
│ ├── otel-collector-config.dev.yaml
│ └── otel-collector-config.prod.yaml
Option 2: Use Docker Compose Overrides
# docker-compose.prod.yml
services:
signoz-otel-collector:
volumes:
- ./config/signoz/otel-collector-config.prod.yaml:/etc/otel-collector-config.yaml
Option 3: Rely on Service-Level Configuration
Since services already set the environment attribute, you can just remove the resource processor from the collector config entirely.