Skip to content

Commit eabe829

Browse files
authored
[exporter/elasticsearch] Add telemetry.log_request_body and telemetry.log_response_body config (#33854)
**Description:** <Describe what has changed.> <!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> - Add `telemetry.log_request_body` and `telemetry.log_response_body` config for debugging. Debug log will contain field `request_body` and/or `response_body` in the same log line instead of separate lines to avoid interleaved log lines. - Change "Request failed" log level to debug. Output: ``` 2024-07-02T14:09:24.983+0100 debug elasticsearchexporter/elasticsearch_bulk.go:67 Request roundtrip completed. {"kind": "exporter", "data_type": "logs", "name": "elasticsearch", "response_body": "{\"version\":{\"number\":\"1.2.3\"}}\n", "path": "/", "method": "GET", "duration": 0.000865486, "status": "200 OK"} 2024-07-02T14:09:24.984+0100 debug elasticsearchexporter/elasticsearch_bulk.go:67 Request roundtrip completed. {"kind": "exporter", "data_type": "logs", "name": "elasticsearch", "request_body": "{\"create\":{\"_index\":\"logs-test-idx\"}}\n{\"@timestamp\":\"2024-07-02T13:09:24.970187592Z\",\"Attributes\":{\"a\":\"test\",\"b\":5,\"batch_index\":\"batch_1\",\"c\":3,\"d\":true,\"item_index\":\"item_1\"},\"Body\":\"Load Generator Counter #0\",\"Scope\":{\"name\":\"\",\"version\":\"\"},\"SeverityNumber\":11,\"SeverityText\":\"INFO3\",\"TraceFlags\":1}\n{\"create\":{\"_index\":\"logs-test-idx\"}}\n{\"@timestamp\":\"2024-07-02T13:09:24.970187592Z\",\"Attributes\":{\"a\":\"test\",\"b\":5,\"batch_index\":\"batch_1\",\"c\":3,\"d\":true,\"item_index\":\"item_2\"},\"Body\":\"Load Generator Counter #1\",\"Scope\":{\"name\":\"\",\"version\":\"\"},\"SeverityNumber\":11,\"SeverityText\":\"INFO3\",\"TraceFlags\":1}\n", "response_body": "{\"took\":0,\"errors\":false,\"items\":[{\"create\":{\"_index\":\"logs-test-idx\",\"_id\":\"\",\"_version\":0,\"result\":\"\",\"status\":201,\"_seq_no\":0,\"_primary_term\":0,\"_shards\":{\"total\":0,\"successful\":0,\"failed\":0},\"error\":{\"type\":\"\",\"reason\":\"\",\"caused_by\":{\"type\":\"\",\"reason\":\"\"}}}},{\"create\":{\"_index\":\"logs-test-idx\",\"_id\":\"\",\"_version\":0,\"result\":\"\",\"status\":201,\"_seq_no\":0,\"_primary_term\":0,\"_shards\":{\"total\":0,\"successful\":0,\"failed\":0},\"error\":{\"type\":\"\",\"reason\":\"\",\"caused_by\":{\"type\":\"\",\"reason\":\"\"}}}}]}\n", "path": "/_bulk", "method": "POST", "duration": 0.000539979, "status": "200 OK"} ``` Required config to log ``` exporters: elasticsearch: telemetry: log_request_body: true log_response_body: true service: telemetry: logs: level: debug ``` For easier analysis, limit the size of request body size. Use `num_workers`=1 and lower `flush.bytes` and/or `flush.interval`. **Link to tracking Issue:** <Issue number if applicable> **Testing:** <Describe what testing was performed and which tests were added.> Manually verified with a modified integration test. **Documentation:** <Describe the documentation added.>
1 parent 94d47eb commit eabe829

File tree

5 files changed

+94
-16
lines changed

5 files changed

+94
-16
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: elasticsearchexporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Introduce experimental `telemetry.log_request_body` and `telemetry.log_response_body` config
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [33854]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

exporter/elasticsearchexporter/README.md

+10
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,16 @@ Settings related to node discovery are:
184184

185185
Node discovery can be disabled by setting `discover.interval` to 0.
186186

187+
### Telemetry settings
188+
189+
The Elasticsearch Exporter's own telemetry settings for testing and debugging purposes.
190+
191+
⚠️ This is experimental and may change at any time.
192+
193+
- `telemetry`:
194+
- `log_request_body` (default=false): Logs Elasticsearch client request body as a field in a log line at DEBUG level. It requires `service::telemetry::logs::level` to be set to `debug`. WARNING: Enabling this config may expose sensitive data.
195+
- `log_response_body` (default=false): Logs Elasticsearch client response body as a field in a log line at DEBUG level. It requires `service::telemetry::logs::level` to be set to `debug`. WARNING: Enabling this config may expose sensitive data.
196+
187197
## Exporting metrics
188198

189199
Metrics support is currently in development.

exporter/elasticsearchexporter/config.go

+9
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,15 @@ type Config struct {
7272
Flush FlushSettings `mapstructure:"flush"`
7373
Mapping MappingsSettings `mapstructure:"mapping"`
7474
LogstashFormat LogstashFormatSettings `mapstructure:"logstash_format"`
75+
76+
// TelemetrySettings contains settings useful for testing/debugging purposes
77+
// This is experimental and may change at any time.
78+
TelemetrySettings `mapstructure:"telemetry"`
79+
}
80+
81+
type TelemetrySettings struct {
82+
LogRequestBody bool `mapstructure:"log_request_body"`
83+
LogResponseBody bool `mapstructure:"log_response_body"`
7584
}
7685

7786
type LogstashFormatSettings struct {

exporter/elasticsearchexporter/elasticsearch_bulk.go

+44-16
Original file line numberDiff line numberDiff line change
@@ -32,37 +32,59 @@ type esBulkIndexerItem = docappender.BulkIndexerItem
3232

3333
// clientLogger implements the estransport.Logger interface
3434
// that is required by the Elasticsearch client for logging.
35-
type clientLogger zap.Logger
35+
type clientLogger struct {
36+
*zap.Logger
37+
logRequestBody bool
38+
logResponseBody bool
39+
}
3640

3741
// LogRoundTrip should not modify the request or response, except for consuming and closing the body.
3842
// Implementations have to check for nil values in request and response.
39-
func (cl *clientLogger) LogRoundTrip(requ *http.Request, resp *http.Response, err error, _ time.Time, dur time.Duration) error {
40-
zl := (*zap.Logger)(cl)
43+
func (cl *clientLogger) LogRoundTrip(requ *http.Request, resp *http.Response, clientErr error, _ time.Time, dur time.Duration) error {
44+
zl := cl.Logger
45+
46+
var fields []zap.Field
47+
if cl.logRequestBody && requ != nil && requ.Body != nil {
48+
if b, err := io.ReadAll(requ.Body); err == nil {
49+
fields = append(fields, zap.ByteString("request_body", b))
50+
}
51+
}
52+
if cl.logResponseBody && resp != nil && resp.Body != nil {
53+
if b, err := io.ReadAll(resp.Body); err == nil {
54+
fields = append(fields, zap.ByteString("response_body", b))
55+
}
56+
}
57+
4158
switch {
42-
case err == nil && resp != nil:
43-
zl.Debug("Request roundtrip completed.",
59+
case clientErr == nil && resp != nil:
60+
fields = append(
61+
fields,
4462
zap.String("path", sanitize.String(requ.URL.Path)),
4563
zap.String("method", requ.Method),
4664
zap.Duration("duration", dur),
47-
zap.String("status", resp.Status))
48-
49-
case err != nil:
50-
zl.Error("Request failed.", zap.NamedError("reason", err))
65+
zap.String("status", resp.Status),
66+
)
67+
zl.Debug("Request roundtrip completed.", fields...)
68+
69+
case clientErr != nil:
70+
fields = append(
71+
fields,
72+
zap.NamedError("reason", clientErr),
73+
)
74+
zl.Debug("Request failed.", fields...)
5175
}
5276

5377
return nil
5478
}
5579

5680
// RequestBodyEnabled makes the client pass a copy of request body to the logger.
57-
func (*clientLogger) RequestBodyEnabled() bool {
58-
// TODO: introduce setting log the bodies for more detailed debug logs
59-
return false
81+
func (cl *clientLogger) RequestBodyEnabled() bool {
82+
return cl.logRequestBody
6083
}
6184

6285
// ResponseBodyEnabled makes the client pass a copy of response body to the logger.
63-
func (*clientLogger) ResponseBodyEnabled() bool {
64-
// TODO: introduce setting log the bodies for more detailed debug logs
65-
return false
86+
func (cl *clientLogger) ResponseBodyEnabled() bool {
87+
return cl.logResponseBody
6688
}
6789

6890
func newElasticsearchClient(
@@ -97,6 +119,12 @@ func newElasticsearchClient(
97119
return nil, err
98120
}
99121

122+
esLogger := clientLogger{
123+
Logger: telemetry.Logger,
124+
logRequestBody: config.LogRequestBody,
125+
logResponseBody: config.LogResponseBody,
126+
}
127+
100128
return elasticsearch7.NewClient(esConfigCurrent{
101129
Transport: httpClient.Transport,
102130

@@ -122,7 +150,7 @@ func newElasticsearchClient(
122150
// configure internal metrics reporting and logging
123151
EnableMetrics: false, // TODO
124152
EnableDebugLogger: false, // TODO
125-
Logger: (*clientLogger)(telemetry.Logger),
153+
Logger: &esLogger,
126154
})
127155
}
128156

exporter/elasticsearchexporter/factory.go

+4
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ func createDefaultConfig() component.Config {
8484
PrefixSeparator: "-",
8585
DateFormat: "%Y.%m.%d",
8686
},
87+
TelemetrySettings: TelemetrySettings{
88+
LogRequestBody: false,
89+
LogResponseBody: false,
90+
},
8791
}
8892
}
8993

0 commit comments

Comments
 (0)