instana 2.9.0 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +173 -0
- data/lib/instana/backend/host_agent_reporting_observer.rb +26 -14
- data/lib/instana/base.rb +5 -0
- data/lib/instana/config.rb +66 -2
- data/lib/instana/exporter/otlp/aws_converter.rb +14 -3
- data/lib/instana/exporter/otlp/background_job_converter.rb +12 -1
- data/lib/instana/exporter/otlp/base_converter.rb +14 -2
- data/lib/instana/exporter/otlp/database_converter.rb +24 -4
- data/lib/instana/exporter/otlp/http_converter.rb +3 -2
- data/lib/instana/exporter/otlp/messaging_converter.rb +67 -21
- data/lib/instana/exporter/otlp/rpc_converter.rb +64 -4
- data/lib/instana/instrumentation/active_job.rb +34 -19
- data/lib/instana/instrumentation/aws_sdk_lambda.rb +16 -7
- data/lib/instana/instrumentation/aws_sdk_sns.rb +31 -1
- data/lib/instana/instrumentation/aws_sdk_sqs.rb +10 -5
- data/lib/instana/instrumentation/bunny.rb +23 -6
- data/lib/instana/instrumentation/grpc.rb +39 -11
- data/lib/instana/instrumentation/instrumented_request.rb +21 -11
- data/lib/instana/instrumentation/rack.rb +2 -0
- data/lib/instana/instrumentation/resque.rb +2 -1
- data/lib/instana/instrumentation/shoryuken.rb +33 -12
- data/lib/instana/instrumentation/sidekiq-client.rb +1 -0
- data/lib/instana/instrumentation/sidekiq-worker.rb +4 -2
- data/lib/instana/trace/span_context.rb +1 -1
- data/lib/instana/util.rb +68 -1
- data/lib/instana/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 651f82ecb4bf26f63225bb880fff4028fca72f641eeac492b3bbb85d4c0be0d2
|
|
4
|
+
data.tar.gz: b311f0c13d53cf688247b580f018a57a62569eb0a1fa5c25d8fac1a8939ffdf0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 29c82de02af9e09ebaa84da9429d70867f1f8eb3c397836d50a78eaddecf8339a6b20e809bbdadc22dbd0f5f8672e766d96aff1c0802f9a08edefd7bccb0a1ae
|
|
7
|
+
data.tar.gz: e099c624a54ce5871010efad8ad469d8aebf0672cc7011a49bd26c9b448fcc6883eb58122cc9424f69757432b418b1a38fe332d78b1718c65ba60cae8958754e
|
data/README.md
CHANGED
|
@@ -51,6 +51,179 @@ Although the gem has no configuration required for out of the box metrics and tr
|
|
|
51
51
|
|
|
52
52
|
This Ruby gem provides a simple API for tracing and also supports [OpenTracing](http://opentracing.io/). See the [Ruby Tracing SDK](https://www.ibm.com/docs/en/instana-observability/current?topic=ruby-tracing-sdk) and [OpenTracing](https://www.ibm.com/docs/en/instana-observability/current?topic=ruby-opentracing) pages for details.
|
|
53
53
|
|
|
54
|
+
## OTLP Export
|
|
55
|
+
|
|
56
|
+
The `instana` gem supports exporting traces via the **OpenTelemetry Protocol (OTLP)**
|
|
57
|
+
directly to the Instana agent's OTLP receiver, bypassing the native agent trace format.
|
|
58
|
+
OTLP export is **opt-in** — the gem behaves identically to previous versions when
|
|
59
|
+
`INSTANA_TRACING_OTLP_ENABLED` is not set.
|
|
60
|
+
|
|
61
|
+
### Overview
|
|
62
|
+
|
|
63
|
+
When OTLP export is enabled:
|
|
64
|
+
- Spans are converted from Instana's internal format to OTLP protobuf
|
|
65
|
+
- The converted spans are sent via HTTP/protobuf to the agent's OTLP port (`4318`)
|
|
66
|
+
- The endpoint is auto-derived from the same host where the Instana agent was discovered
|
|
67
|
+
- The native agent reporting path (`/com.instana.plugin.ruby/traces`) is replaced by OTLP
|
|
68
|
+
|
|
69
|
+
### Quick Start
|
|
70
|
+
|
|
71
|
+
The only required change is setting one environment variable before starting your application:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
INSTANA_TRACING_OTLP_ENABLED=true bundle exec rails server
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Expected log output (with `INSTANA_LOG_LEVEL=debug`):
|
|
78
|
+
```
|
|
79
|
+
[Instana] Using OTLP Exporter to export result code: 0
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Result code `0` = `SUCCESS`. No other configuration is needed — the endpoint is
|
|
83
|
+
automatically set to `http://<agent-host>:4318/v1/traces`.
|
|
84
|
+
|
|
85
|
+
### Gem Dependencies
|
|
86
|
+
|
|
87
|
+
`opentelemetry-exporter-otlp` is a **runtime dependency** of the `instana` gem and
|
|
88
|
+
is installed automatically. No additional gems are required.
|
|
89
|
+
|
|
90
|
+
> **Note:** gRPC (`OTEL_EXPORTER_OTLP_PROTOCOL=grpc`) is not supported.
|
|
91
|
+
> Only `http/protobuf` is supported and tested.
|
|
92
|
+
|
|
93
|
+
### Environment Variables
|
|
94
|
+
|
|
95
|
+
| Variable | Type | Default | Description |
|
|
96
|
+
|---|---|---|---|
|
|
97
|
+
| `INSTANA_TRACING_OTLP_ENABLED` | Boolean | `false` | Enables OTLP export. Valid values: `true`, `1`, `yes` |
|
|
98
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | String (URL) | auto-derived from agent host | **Base** endpoint URL. `/v1/traces` is appended automatically. |
|
|
99
|
+
| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | String (URL) | `<OTEL_EXPORTER_OTLP_ENDPOINT>/v1/traces` | **Fully-qualified** trace endpoint. Used as-is; overrides `OTEL_EXPORTER_OTLP_ENDPOINT`. |
|
|
100
|
+
| `OTEL_EXPORTER_OTLP_PROTOCOL` | String | `http/protobuf` | Transport protocol. Only `http/protobuf` is supported. |
|
|
101
|
+
| `OTEL_EXPORTER_OTLP_HEADERS` | String | — | Comma-separated `key=value` auth headers. e.g. `api-key=secret,x-tenant-id=myorg` |
|
|
102
|
+
| `OTEL_EXPORTER_OTLP_TIMEOUT` | Integer (ms) | `10000` | Maximum time to wait for export completion. |
|
|
103
|
+
| `OTEL_EXPORTER_OTLP_COMPRESSION` | String | — | Compression algorithm. Valid value: `gzip`. |
|
|
104
|
+
| `OTEL_EXPORTER_OTLP_CERTIFICATE` | String (path) | — | Path to CA certificate file for TLS verification. |
|
|
105
|
+
| `OTEL_EXPORTER_OTLP_CLIENT_KEY` | String (path) | — | Path to client private key file for mutual TLS. |
|
|
106
|
+
| `OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE` | String (path) | — | Path to client certificate file for mutual TLS. |
|
|
107
|
+
| `OTEL_EXPORTER_OTLP_INSECURE` | Boolean | `false` | Disable TLS certificate verification. |
|
|
108
|
+
| `OTEL_SEMCONV_STABILITY_OPT_IN` | String | `stable` | Semantic convention stability level. Valid values: `stable`, `development`. |
|
|
109
|
+
|
|
110
|
+
> **Endpoint precedence:** `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` > `OTEL_EXPORTER_OTLP_ENDPOINT` > auto-derived from agent host
|
|
111
|
+
|
|
112
|
+
### YAML Configuration
|
|
113
|
+
|
|
114
|
+
When `INSTANA_CONFIG_PATH` points to a YAML file, OTLP settings are placed under
|
|
115
|
+
the `tracing.otlp` key. YAML configuration takes precedence over environment variables.
|
|
116
|
+
|
|
117
|
+
**Minimal example** (`config/instana.yml`):
|
|
118
|
+
```yaml
|
|
119
|
+
tracing:
|
|
120
|
+
otlp:
|
|
121
|
+
enabled: true
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Full example:**
|
|
125
|
+
```yaml
|
|
126
|
+
tracing:
|
|
127
|
+
otlp:
|
|
128
|
+
enabled: true
|
|
129
|
+
endpoint: "http://localhost:4318/v1/traces"
|
|
130
|
+
protocol: "http/protobuf"
|
|
131
|
+
timeout: 10000
|
|
132
|
+
compression: "gzip"
|
|
133
|
+
headers:
|
|
134
|
+
x-instana-key: "YOUR_API_KEY"
|
|
135
|
+
x-tenant-id: "YOUR_TENANT"
|
|
136
|
+
certificate: "/path/to/ca-cert.pem"
|
|
137
|
+
client_key: "/path/to/client-key.pem"
|
|
138
|
+
client_certificate: "/path/to/client-cert.pem"
|
|
139
|
+
insecure: false
|
|
140
|
+
semconv_stability: "stable"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Start the application:
|
|
144
|
+
```bash
|
|
145
|
+
INSTANA_CONFIG_PATH=config/instana.yml bundle exec rails server
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Configuration Precedence
|
|
149
|
+
|
|
150
|
+
Settings are resolved in this order (highest wins):
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
INSTANA_CONFIG_PATH YAML → Environment variables → Agent config → Defaults
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This means a YAML file always wins over env vars. Agent-provided config (pushed
|
|
157
|
+
via the Instana agent's discovery payload) is applied after env vars but can be
|
|
158
|
+
overridden by YAML or env vars set at startup.
|
|
159
|
+
|
|
160
|
+
### TLS / mTLS
|
|
161
|
+
|
|
162
|
+
**Server-side TLS** (verify the collector's certificate):
|
|
163
|
+
```bash
|
|
164
|
+
INSTANA_TRACING_OTLP_ENABLED=true \
|
|
165
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=https://your-collector:4318/v1/traces \
|
|
166
|
+
OTEL_EXPORTER_OTLP_CERTIFICATE=/path/to/ca-cert.pem \
|
|
167
|
+
bundle exec rails server
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Mutual TLS** (client certificate authentication):
|
|
171
|
+
```bash
|
|
172
|
+
INSTANA_TRACING_OTLP_ENABLED=true \
|
|
173
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=https://your-collector:4318/v1/traces \
|
|
174
|
+
OTEL_EXPORTER_OTLP_CERTIFICATE=/path/to/ca-cert.pem \
|
|
175
|
+
OTEL_EXPORTER_OTLP_CLIENT_KEY=/path/to/client-key.pem \
|
|
176
|
+
OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE=/path/to/client-cert.pem \
|
|
177
|
+
bundle exec rails server
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Troubleshooting
|
|
181
|
+
|
|
182
|
+
**OTLP export is not happening — spans go via the native path**
|
|
183
|
+
|
|
184
|
+
OTLP is disabled by default. Check that `INSTANA_TRACING_OTLP_ENABLED=true` is set
|
|
185
|
+
in the process environment before the gem initialises (i.e. before `require 'instana'`
|
|
186
|
+
or Rails boot). Verify with:
|
|
187
|
+
```bash
|
|
188
|
+
INSTANA_LOG_LEVEL=debug bundle exec rails server
|
|
189
|
+
# Look for: "Using OTLP Exporter" vs "Using Instana Native Exporter"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**`Failed to initialize OTLP exporter` in the log**
|
|
193
|
+
|
|
194
|
+
The exporter could not be constructed. Common causes:
|
|
195
|
+
- `OTEL_EXPORTER_OTLP_CERTIFICATE` path does not exist or is not readable
|
|
196
|
+
- `OTEL_EXPORTER_OTLP_CLIENT_KEY` / `OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE` path invalid
|
|
197
|
+
- An unsupported protocol (e.g. `grpc`) was set — only `http/protobuf` is supported
|
|
198
|
+
|
|
199
|
+
The gem falls back to `@otlp_exporter = nil` and logs an `ERROR` line with the
|
|
200
|
+
exception message. Check that message for the root cause.
|
|
201
|
+
|
|
202
|
+
**`result code: 1` (FAILURE) — spans not arriving**
|
|
203
|
+
|
|
204
|
+
The exporter initialised but the export request failed. Common causes:
|
|
205
|
+
- The Instana agent is not running or OTLP is not enabled on the agent side
|
|
206
|
+
- `OTEL_EXPORTER_OTLP_ENDPOINT` points to a wrong host or port
|
|
207
|
+
- `OTEL_EXPORTER_OTLP_ENDPOINT` was set to a base URL like `http://host:4318`
|
|
208
|
+
without `/v1/traces` — this was a known bug fixed in v2.9.0 (the sensor now
|
|
209
|
+
appends the path automatically)
|
|
210
|
+
- A firewall is blocking port `4318`
|
|
211
|
+
|
|
212
|
+
Verify the agent OTLP port is reachable:
|
|
213
|
+
```bash
|
|
214
|
+
curl -s -o /dev/null -w "%{http_code}" \
|
|
215
|
+
-X POST http://localhost:4318/v1/traces \
|
|
216
|
+
-H "Content-Type: application/x-protobuf"
|
|
217
|
+
# 200 or 415 = port open; "connection refused" = agent OTLP not enabled
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**`HTTP request path is empty` exception (pre-v2.9.0)**
|
|
221
|
+
|
|
222
|
+
If you are on a version earlier than 2.9.0 and pass a base URL to
|
|
223
|
+
`OTEL_EXPORTER_OTLP_ENDPOINT` (without `/v1/traces`), the `opentelemetry-exporter-otlp`
|
|
224
|
+
gem crashes with `HTTP request path is empty`. Upgrade to v2.9.0 or later, or use
|
|
225
|
+
`OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` with the full path instead.
|
|
226
|
+
|
|
54
227
|
## Documentation
|
|
55
228
|
|
|
56
229
|
You can find more documentation covering supported components and minimum versions in the Instana [documentation portal](https://www.ibm.com/docs/en/instana-observability/current?topic=technologies-monitoring-ruby).
|
|
@@ -186,11 +186,12 @@ module Instana
|
|
|
186
186
|
|
|
187
187
|
endpoint = resolve_otlp_endpoint(config[:endpoint], config[:config_source])
|
|
188
188
|
opts = { endpoint: endpoint, timeout: config[:timeout] / 1000.0 }
|
|
189
|
-
opts[:compression]
|
|
190
|
-
opts[:headers]
|
|
191
|
-
opts[:certificate_file]
|
|
192
|
-
opts[:client_certificate_file] = config[:client_certificate]
|
|
193
|
-
opts[:client_key_file]
|
|
189
|
+
opts[:compression] = config[:compression] if config[:compression]
|
|
190
|
+
opts[:headers] = config[:headers] if config[:headers]&.any?
|
|
191
|
+
opts[:certificate_file] = config[:certificate] if config[:certificate]
|
|
192
|
+
opts[:client_certificate_file] = config[:client_certificate] if config[:client_certificate]
|
|
193
|
+
opts[:client_key_file] = config[:client_key] if config[:client_key]
|
|
194
|
+
opts[:ssl_verify_mode] = OpenSSL::SSL::VERIFY_NONE if config[:insecure]
|
|
194
195
|
|
|
195
196
|
@otlp_exporter = OpenTelemetry::Exporter::OTLP::Exporter.new(**opts)
|
|
196
197
|
rescue StandardError => e
|
|
@@ -198,21 +199,32 @@ module Instana
|
|
|
198
199
|
@otlp_exporter = nil
|
|
199
200
|
end
|
|
200
201
|
|
|
201
|
-
# Derive the OTLP endpoint from the discovered agent host when no explicit
|
|
202
|
-
# endpoint has been configured (config_source == 'default').
|
|
203
202
|
OTLP_DEFAULT_PORT = 4318
|
|
204
203
|
OTLP_TRACES_PATH = '/v1/traces'.freeze
|
|
205
204
|
|
|
205
|
+
# Returns a fully-qualified OTLP traces endpoint.
|
|
206
|
+
#
|
|
207
|
+
# When config_source is 'default', builds the endpoint from the discovered
|
|
208
|
+
# agent host so OTLP traffic goes to the same host as metrics/traces.
|
|
209
|
+
#
|
|
210
|
+
# For user-supplied endpoints, appends '/v1/traces' when the URL has no
|
|
211
|
+
# path, because OTEL_EXPORTER_OTLP_ENDPOINT is a base URL and the
|
|
212
|
+
# opentelemetry-exporter-otlp gem only auto-appends the path when no
|
|
213
|
+
# endpoint is given at all.
|
|
206
214
|
def resolve_otlp_endpoint(endpoint, config_source)
|
|
207
|
-
|
|
215
|
+
if config_source == 'default'
|
|
216
|
+
agent_host = @client&.host
|
|
217
|
+
return endpoint unless agent_host
|
|
208
218
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
# OTLP HTTP port and traces path.
|
|
212
|
-
agent_host = @client&.host
|
|
213
|
-
return endpoint unless agent_host
|
|
219
|
+
return "http://#{agent_host}:#{OTLP_DEFAULT_PORT}#{OTLP_TRACES_PATH}"
|
|
220
|
+
end
|
|
214
221
|
|
|
215
|
-
|
|
222
|
+
# User-supplied: append the traces path if no path was given.
|
|
223
|
+
uri = URI.parse(endpoint)
|
|
224
|
+
uri.path = OTLP_TRACES_PATH if uri.path.empty? || uri.path == '/'
|
|
225
|
+
uri.to_s
|
|
226
|
+
rescue URI::InvalidURIError
|
|
227
|
+
endpoint
|
|
216
228
|
end
|
|
217
229
|
end
|
|
218
230
|
end
|
data/lib/instana/base.rb
CHANGED
|
@@ -6,6 +6,11 @@ require "instana/version"
|
|
|
6
6
|
require "instana/util"
|
|
7
7
|
|
|
8
8
|
module Instana
|
|
9
|
+
# Instana trace context header names
|
|
10
|
+
INSTANA_TRACE_ID_HEADER = 'X-Instana-T'.freeze
|
|
11
|
+
INSTANA_SPAN_ID_HEADER = 'X-Instana-S'.freeze
|
|
12
|
+
INSTANA_LEVEL_HEADER = 'X-Instana-L'.freeze
|
|
13
|
+
|
|
9
14
|
class << self
|
|
10
15
|
attr_accessor :agent
|
|
11
16
|
attr_accessor :tracer
|
data/lib/instana/config.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
require 'yaml'
|
|
5
5
|
|
|
6
6
|
module Instana
|
|
7
|
-
class Config
|
|
7
|
+
class Config # rubocop:disable Metrics/ClassLength
|
|
8
8
|
|
|
9
9
|
LEGACY_TRACING_KEY = 'com.instana.tracing'.freeze
|
|
10
10
|
TRACING_KEY = 'tracing'.freeze
|
|
@@ -63,6 +63,9 @@ module Instana
|
|
|
63
63
|
certificate: nil,
|
|
64
64
|
client_key: nil,
|
|
65
65
|
client_certificate: nil,
|
|
66
|
+
protocol: 'http/protobuf',
|
|
67
|
+
semconv_stability: 'stable',
|
|
68
|
+
insecure: false,
|
|
66
69
|
config_source: 'default'
|
|
67
70
|
}
|
|
68
71
|
read_otlp_config
|
|
@@ -80,6 +83,10 @@ module Instana
|
|
|
80
83
|
# W3C Trace Context Support
|
|
81
84
|
@config[:w3c_trace_correlation] = ENV.fetch('INSTANA_DISABLE_W3C_TRACE_CORRELATION', nil).nil?
|
|
82
85
|
|
|
86
|
+
# Server-Timing response header injection (default: injected)
|
|
87
|
+
# Priority: YAML > env var > agent config > default (false)
|
|
88
|
+
read_disable_server_timing_config
|
|
89
|
+
|
|
83
90
|
# HTTP exit span 4xx error classification (opt-in, default: off)
|
|
84
91
|
# Priority: env vars > agent config > default (false / [])
|
|
85
92
|
read_http_exit_config
|
|
@@ -148,6 +155,8 @@ module Instana
|
|
|
148
155
|
read_otlp_config_from_agent(tracing_config) if should_read_from_agent?(:otlp)
|
|
149
156
|
# Read HTTP exit 4xx classification from agent if env vars did not already set it
|
|
150
157
|
read_http_exit_classification_from_agent(tracing_config) unless env_http_exit_classification_set?
|
|
158
|
+
# Read Server-Timing disable flag from agent if not already set from YAML or env
|
|
159
|
+
read_disable_server_timing_from_agent(tracing_config) if @config[:disable_server_timing_source] == 'default'
|
|
151
160
|
# Read span filtering configuration from agent
|
|
152
161
|
::Instana.span_filtering_config&.read_config_from_agent(discovery)
|
|
153
162
|
rescue => e
|
|
@@ -257,11 +266,57 @@ module Instana
|
|
|
257
266
|
@config[:otlp][:certificate] = otlp_config['certificate'] if otlp_config['certificate']
|
|
258
267
|
@config[:otlp][:client_key] = otlp_config['client_key'] if otlp_config['client_key']
|
|
259
268
|
@config[:otlp][:client_certificate] = otlp_config['client_certificate'] if otlp_config['client_certificate']
|
|
269
|
+
@config[:otlp][:protocol] = otlp_config['protocol'] if otlp_config['protocol']
|
|
270
|
+
@config[:otlp][:semconv_stability] = otlp_config['semconv_stability'] if otlp_config['semconv_stability']
|
|
271
|
+
@config[:otlp][:insecure] = truthy?(otlp_config['insecure']) unless otlp_config['insecure'].nil?
|
|
260
272
|
@config[:otlp][:config_source] = 'agent'
|
|
261
273
|
end
|
|
262
274
|
|
|
263
275
|
private
|
|
264
276
|
|
|
277
|
+
# Read disable-server-timing from YAML (tracing.global) or INSTANA_TRACING_DISABLE_SERVER_TIMING.
|
|
278
|
+
# Agent value is applied later via read_config_from_agent if neither is set.
|
|
279
|
+
def read_disable_server_timing_config
|
|
280
|
+
@config[:disable_server_timing] = false
|
|
281
|
+
@config[:disable_server_timing_source] = 'default'
|
|
282
|
+
|
|
283
|
+
yaml_value = parse_disable_server_timing_from_yaml
|
|
284
|
+
unless yaml_value.nil?
|
|
285
|
+
@config[:disable_server_timing] = truthy?(yaml_value)
|
|
286
|
+
@config[:disable_server_timing_source] = 'yaml'
|
|
287
|
+
return
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
env_value = ENV.fetch('INSTANA_TRACING_DISABLE_SERVER_TIMING', nil)
|
|
291
|
+
return if env_value.nil? || env_value.strip.empty?
|
|
292
|
+
|
|
293
|
+
@config[:disable_server_timing] = truthy?(env_value.strip)
|
|
294
|
+
@config[:disable_server_timing_source] = 'env'
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# @return [Object, nil] raw YAML value of tracing.global.disable-server-timing, or nil if not set
|
|
298
|
+
def parse_disable_server_timing_from_yaml
|
|
299
|
+
config_path = ENV.fetch('INSTANA_CONFIG_PATH', nil)
|
|
300
|
+
return nil unless config_path && File.exist?(config_path)
|
|
301
|
+
|
|
302
|
+
yaml_content = YAML.safe_load(File.read(config_path))
|
|
303
|
+
tracing_config = yaml_content[TRACING_KEY] || yaml_content[LEGACY_TRACING_KEY]
|
|
304
|
+
global_config = tracing_config && tracing_config['global']
|
|
305
|
+
global_config.is_a?(Hash) ? global_config['disable-server-timing'] : nil
|
|
306
|
+
rescue => e
|
|
307
|
+
::Instana.logger.warn("Failed to load disable-server-timing configuration from YAML: #{e.message}")
|
|
308
|
+
nil
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# @param tracing_config [Hash] the tracing sub-hash from the discovery payload
|
|
312
|
+
def read_disable_server_timing_from_agent(tracing_config)
|
|
313
|
+
global_config = tracing_config['global']
|
|
314
|
+
return unless global_config.is_a?(Hash) && !global_config['disable-server-timing'].nil?
|
|
315
|
+
|
|
316
|
+
@config[:disable_server_timing] = truthy?(global_config['disable-server-timing'])
|
|
317
|
+
@config[:disable_server_timing_source] = 'agent'
|
|
318
|
+
end
|
|
319
|
+
|
|
265
320
|
# Read HTTP exit 4xx error classification config (wrapper — same pattern as read_span_stack_config / read_otlp_config)
|
|
266
321
|
def read_http_exit_config
|
|
267
322
|
@config[:http_exit_classify_all_4xx_as_errors] = false
|
|
@@ -381,6 +436,9 @@ module Instana
|
|
|
381
436
|
result[:certificate] = otlp_yaml['certificate'] if otlp_yaml['certificate']
|
|
382
437
|
result[:client_key] = otlp_yaml['client_key'] if otlp_yaml['client_key']
|
|
383
438
|
result[:client_certificate] = otlp_yaml['client_certificate'] if otlp_yaml['client_certificate']
|
|
439
|
+
result[:protocol] = otlp_yaml['protocol'] if otlp_yaml['protocol']
|
|
440
|
+
result[:semconv_stability] = otlp_yaml['semconv_stability'] if otlp_yaml['semconv_stability']
|
|
441
|
+
result[:insecure] = truthy?(otlp_yaml['insecure']) unless otlp_yaml['insecure'].nil?
|
|
384
442
|
result.empty? ? nil : result
|
|
385
443
|
end
|
|
386
444
|
|
|
@@ -399,6 +457,9 @@ module Instana
|
|
|
399
457
|
result[:certificate] = raw[:certificate] if raw[:certificate]
|
|
400
458
|
result[:client_key] = raw[:client_key] if raw[:client_key]
|
|
401
459
|
result[:client_certificate] = raw[:client_cert] if raw[:client_cert]
|
|
460
|
+
result[:protocol] = raw[:protocol] if raw[:protocol]
|
|
461
|
+
result[:semconv_stability] = raw[:semconv_stability] if raw[:semconv_stability]
|
|
462
|
+
result[:insecure] = truthy?(raw[:insecure_raw]) unless raw[:insecure_raw].nil?
|
|
402
463
|
result
|
|
403
464
|
end
|
|
404
465
|
|
|
@@ -413,7 +474,10 @@ module Instana
|
|
|
413
474
|
headers_raw: ENV.fetch('OTEL_EXPORTER_OTLP_TRACES_HEADERS', nil) || ENV.fetch('OTEL_EXPORTER_OTLP_HEADERS', nil),
|
|
414
475
|
certificate: ENV.fetch('OTEL_EXPORTER_OTLP_CERTIFICATE', nil),
|
|
415
476
|
client_key: ENV.fetch('OTEL_EXPORTER_OTLP_CLIENT_KEY', nil),
|
|
416
|
-
client_cert: ENV.fetch('OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE', nil)
|
|
477
|
+
client_cert: ENV.fetch('OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE', nil),
|
|
478
|
+
protocol: ENV.fetch('OTEL_EXPORTER_OTLP_PROTOCOL', nil),
|
|
479
|
+
semconv_stability: ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', nil),
|
|
480
|
+
insecure_raw: ENV.fetch('OTEL_EXPORTER_OTLP_INSECURE', nil)
|
|
417
481
|
}
|
|
418
482
|
end
|
|
419
483
|
|
|
@@ -6,6 +6,9 @@ require_relative 'base_converter'
|
|
|
6
6
|
require 'opentelemetry/semconv/incubating/messaging'
|
|
7
7
|
require 'opentelemetry/semconv/db'
|
|
8
8
|
require 'opentelemetry/semconv/incubating/db'
|
|
9
|
+
require 'opentelemetry/semconv/incubating/rpc'
|
|
10
|
+
require 'opentelemetry/semconv/incubating/cloud'
|
|
11
|
+
require 'opentelemetry/semconv/incubating/faas'
|
|
9
12
|
|
|
10
13
|
module Instana
|
|
11
14
|
module Exporter
|
|
@@ -128,10 +131,18 @@ module Instana
|
|
|
128
131
|
def convert_s3_attributes(attributes, s3_data)
|
|
129
132
|
return unless s3_data
|
|
130
133
|
|
|
131
|
-
add_attribute(attributes,
|
|
134
|
+
add_attribute(attributes, Instana::Exporter::Otlp::RPC_SYSTEM_ATTR, 'aws-api')
|
|
135
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::RPC::RPC_METHOD, s3_rpc_method(s3_data[:op]))
|
|
136
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::CLOUD::CLOUD_PROVIDER, 'aws')
|
|
137
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::CLOUD::CLOUD_REGION, s3_data[:region])
|
|
132
138
|
add_attribute(attributes, 'aws.s3.bucket', s3_data[:bucket])
|
|
133
139
|
add_attribute(attributes, 'aws.s3.key', s3_data[:key])
|
|
134
|
-
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def s3_rpc_method(operation)
|
|
143
|
+
return unless operation
|
|
144
|
+
|
|
145
|
+
"S3.#{operation}"
|
|
135
146
|
end
|
|
136
147
|
|
|
137
148
|
def convert_lambda_attributes(attributes, lambda_data)
|
|
@@ -140,7 +151,7 @@ module Instana
|
|
|
140
151
|
add_attribute(attributes, 'aws.service', 'lambda')
|
|
141
152
|
add_attribute(attributes, 'aws.lambda.function_name', lambda_data[:function])
|
|
142
153
|
add_attribute(attributes, 'aws.lambda.invocation_type', lambda_data[:type])
|
|
143
|
-
add_attribute(attributes,
|
|
154
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::FAAS::FAAS_INVOKED_NAME, lambda_data[:function])
|
|
144
155
|
end
|
|
145
156
|
end
|
|
146
157
|
end
|
|
@@ -41,6 +41,8 @@ module Instana
|
|
|
41
41
|
convert_job_attributes(attributes, span[:'resque-client'] || span[:data]&.[](:'resque-client'), 'resque', 'publish')
|
|
42
42
|
elsif span_type == 'resque-worker'
|
|
43
43
|
convert_job_attributes(attributes, span[:'resque-worker'] || span[:data]&.[](:'resque-worker'), 'resque', 'process')
|
|
44
|
+
elsif span_type == 'activejob'
|
|
45
|
+
convert_activejob_attributes(attributes, span[:data]&.[](:activejob))
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
attributes
|
|
@@ -53,13 +55,22 @@ module Instana
|
|
|
53
55
|
|
|
54
56
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_SYSTEM, system)
|
|
55
57
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_DESTINATION_NAME, data[:queue] || data['queue'])
|
|
56
|
-
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::
|
|
58
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_OPERATION_NAME, operation)
|
|
57
59
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_MESSAGE_ID, data[:job_id] || data['job_id'])
|
|
58
60
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_CONSUMER_GROUP_NAME, data[:job] || data['job'])
|
|
59
61
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, extract_host(data[:'redis-url'] || data['redis-url']))
|
|
60
62
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_PORT, extract_port(data[:'redis-url'] || data['redis-url']))
|
|
61
63
|
end
|
|
62
64
|
|
|
65
|
+
def convert_activejob_attributes(attributes, data)
|
|
66
|
+
return unless data
|
|
67
|
+
|
|
68
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_SYSTEM, 'activejob')
|
|
69
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_DESTINATION_NAME, data[:queue] || data['queue'])
|
|
70
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_OPERATION_NAME, data[:action] || data['action'])
|
|
71
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_MESSAGE_ID, data[:job_id] || data['job_id'])
|
|
72
|
+
end
|
|
73
|
+
|
|
63
74
|
def extract_host(connection)
|
|
64
75
|
return nil unless connection
|
|
65
76
|
|
|
@@ -5,10 +5,22 @@
|
|
|
5
5
|
require_relative 'resource'
|
|
6
6
|
require 'opentelemetry/trace'
|
|
7
7
|
require 'forwardable'
|
|
8
|
+
require 'opentelemetry/semconv/incubating/rpc'
|
|
8
9
|
|
|
9
10
|
module Instana
|
|
10
11
|
module Exporter
|
|
11
12
|
module Otlp
|
|
13
|
+
# Compatibility shim: RPC_SYSTEM_NAME was added in a newer release of
|
|
14
|
+
# opentelemetry-semantic_conventions. Fall back to the deprecated
|
|
15
|
+
# RPC_SYSTEM constant ('rpc.system') on older installs (e.g. Ruby 3.2
|
|
16
|
+
# lockfiles that resolve an earlier gem version).
|
|
17
|
+
RPC_SYSTEM_ATTR =
|
|
18
|
+
if OpenTelemetry::SemConv::Incubating::RPC.const_defined?(:RPC_SYSTEM_NAME)
|
|
19
|
+
OpenTelemetry::SemConv::Incubating::RPC::RPC_SYSTEM_NAME
|
|
20
|
+
else
|
|
21
|
+
OpenTelemetry::SemConv::Incubating::RPC::RPC_SYSTEM
|
|
22
|
+
end
|
|
23
|
+
|
|
12
24
|
# Base class for all OTLP span converters
|
|
13
25
|
#
|
|
14
26
|
# Provides common interface and shared functionality for converting Instana spans
|
|
@@ -312,12 +324,12 @@ module Instana
|
|
|
312
324
|
timestamp = calculate_end_timestamp
|
|
313
325
|
|
|
314
326
|
if stacktrace
|
|
315
|
-
attrs = {
|
|
327
|
+
attrs = {}
|
|
316
328
|
attrs['exception.message'] = error_msg if error_msg
|
|
317
329
|
attrs['exception.stacktrace'] = stacktrace
|
|
318
330
|
[Event.new('exception', attrs, timestamp)]
|
|
319
331
|
else
|
|
320
|
-
[Event.new('error', {
|
|
332
|
+
[Event.new('error', {}, timestamp)]
|
|
321
333
|
end
|
|
322
334
|
end
|
|
323
335
|
|
|
@@ -82,32 +82,51 @@ module Instana
|
|
|
82
82
|
parts.empty? ? 'mongodb' : parts.join('.')
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
+
# Normalize an ActiveRecord/Sequel adapter name to OTel db.system.name.
|
|
86
|
+
# Only adapters that are actively instrumented and tested are listed here.
|
|
87
|
+
DB_SYSTEM_NORMALIZATION = {
|
|
88
|
+
'mysql2' => 'mysql',
|
|
89
|
+
'sqlite3' => 'sqlite',
|
|
90
|
+
'postgresql' => 'postgresql',
|
|
91
|
+
'mysql' => 'mysql',
|
|
92
|
+
'sqlite' => 'sqlite'
|
|
93
|
+
}.freeze
|
|
94
|
+
|
|
95
|
+
def normalize_db_system(adapter)
|
|
96
|
+
return unless adapter
|
|
97
|
+
|
|
98
|
+
DB_SYSTEM_NORMALIZATION.fetch(adapter.to_s.downcase, adapter.to_s.downcase)
|
|
99
|
+
end
|
|
100
|
+
|
|
85
101
|
def convert_activerecord_attributes(attributes, ar_data)
|
|
86
102
|
return unless ar_data
|
|
87
103
|
|
|
88
|
-
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_SYSTEM_NAME, ar_data[:adapter])
|
|
104
|
+
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_SYSTEM_NAME, normalize_db_system(ar_data[:adapter]))
|
|
89
105
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_NAMESPACE, ar_data[:db])
|
|
90
106
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_QUERY_TEXT, ar_data[:sql])
|
|
91
107
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::DB::DB_USER, ar_data[:username])
|
|
92
108
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, ar_data[:host])
|
|
109
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::DB::DB_COLLECTION_NAME, ar_data[:table])
|
|
93
110
|
end
|
|
94
111
|
|
|
95
112
|
def convert_sequel_attributes(attributes, seq_data)
|
|
96
113
|
return unless seq_data
|
|
97
114
|
|
|
98
|
-
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_SYSTEM_NAME, seq_data[:adapter])
|
|
115
|
+
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_SYSTEM_NAME, normalize_db_system(seq_data[:adapter]))
|
|
99
116
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_NAMESPACE, seq_data[:db])
|
|
100
117
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_QUERY_TEXT, seq_data[:sql])
|
|
101
118
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::DB::DB_USER, seq_data[:username])
|
|
102
119
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, seq_data[:host])
|
|
120
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::DB::DB_COLLECTION_NAME, seq_data[:table])
|
|
103
121
|
end
|
|
104
122
|
|
|
105
123
|
def convert_redis_attributes(attributes, redis_data)
|
|
106
124
|
return unless redis_data
|
|
107
125
|
|
|
108
126
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_SYSTEM_NAME, 'redis')
|
|
127
|
+
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_OPERATION_NAME, redis_data[:command])
|
|
109
128
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_QUERY_TEXT, redis_data[:command])
|
|
110
|
-
add_attribute(attributes,
|
|
129
|
+
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_NAMESPACE, redis_data[:db]&.to_s)
|
|
111
130
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, extract_host(redis_data[:connection]))
|
|
112
131
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_PORT, extract_port(redis_data[:connection]))
|
|
113
132
|
end
|
|
@@ -119,7 +138,7 @@ module Instana
|
|
|
119
138
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_OPERATION_NAME, mc_data[:command])
|
|
120
139
|
add_attribute(attributes, 'db.memcached.key', mc_data[:key])
|
|
121
140
|
add_attribute(attributes, 'db.memcached.keys', mc_data[:keys])
|
|
122
|
-
add_attribute(attributes,
|
|
141
|
+
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_NAMESPACE, mc_data[:namespace])
|
|
123
142
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, extract_host(mc_data[:server]))
|
|
124
143
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_PORT, extract_port(mc_data[:server]))
|
|
125
144
|
end
|
|
@@ -131,6 +150,7 @@ module Instana
|
|
|
131
150
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_NAMESPACE, mongo_data[:namespace])
|
|
132
151
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_OPERATION_NAME, mongo_data[:command])
|
|
133
152
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_QUERY_TEXT, mongo_data[:json])
|
|
153
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::DB::DB_COLLECTION_NAME, mongo_data[:collection])
|
|
134
154
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, mongo_data.dig(:peer, :hostname))
|
|
135
155
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_PORT, mongo_data.dig(:peer, :port))
|
|
136
156
|
end
|
|
@@ -7,6 +7,7 @@ require 'opentelemetry/semconv/http'
|
|
|
7
7
|
require 'opentelemetry/semconv/url'
|
|
8
8
|
require 'opentelemetry/semconv/server'
|
|
9
9
|
require 'opentelemetry/semconv/user_agent'
|
|
10
|
+
require 'opentelemetry/semconv/network'
|
|
10
11
|
|
|
11
12
|
module Instana
|
|
12
13
|
module Exporter
|
|
@@ -120,8 +121,8 @@ module Instana
|
|
|
120
121
|
name = parts[0].downcase
|
|
121
122
|
version = parts[1]
|
|
122
123
|
|
|
123
|
-
add_attribute(attributes,
|
|
124
|
-
add_attribute(attributes,
|
|
124
|
+
add_attribute(attributes, OpenTelemetry::SemConv::NETWORK::NETWORK_PROTOCOL_NAME, name)
|
|
125
|
+
add_attribute(attributes, OpenTelemetry::SemConv::NETWORK::NETWORK_PROTOCOL_VERSION, version)
|
|
125
126
|
end
|
|
126
127
|
end
|
|
127
128
|
end
|