Skip to content

Commit 9d57f7e

Browse files
afharogsoldevilacursoragent
authored
[Kibana Debugging] Improve docs and make it easier to configure OTel + RUM (elastic#270588)
## Summary Since we moved to OTel Traces, we should update our existing docs (https://www.elastic.co/docs/extend/kibana/kibana-debugging#_instrumenting_with_elastic_apm) with how to set up OTel in Kibana. ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [x] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [x] This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The `release_note:breaking` label should be applied in these situations. - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) - [x] Review the [backport guidelines](https://docs.google.com/document/d/1VyN5k91e5OVumlc0Gb9RPa3h1ewuPE705nRtioPiTvY/edit?usp=sharing) and apply applicable `backport:*` labels. --------- Co-authored-by: Gerard Soldevila <gerard.soldevila@elastic.co> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 7b79638 commit 9d57f7e

3 files changed

Lines changed: 213 additions & 39 deletions

File tree

docs/extend/kibana-debugging.md

Lines changed: 106 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,98 @@ mapped_pages:
77

88
For information about how to debug unit tests, refer to [Debugging Unit Tests](/extend/development-tests.md#debugging-unit-tests).
99

10-
1110
## Server Code [_server_code]
1211

1312
`yarn debug` will start the server with Node’s inspect flag. {{kib}}'s development mode will start three processes on ports `9229`, `9230`, and `9231`. Chrome’s developer tools need to be configured to connect to all three connections. Add `localhost:<port>` for each {{kib}} process in Chrome’s developer tools connection tab.
1413

14+
## Instrumenting with OTel Traces [_instrumenting_with_otel_traces]
15+
16+
{{kib}} has built-in OpenTelemetry instrumentation for debugging and observability. The following sections cover tracing configuration.
17+
18+
To enable OTel traces, apply the following configuration:
19+
20+
```yaml
21+
telemetry.tracing:
22+
enabled: true
23+
sample_rate: 1 # 1 by default
24+
exporters:
25+
- proto:
26+
url: <URL_TO_THE_OTLP_ENDPOINT>
27+
headers:
28+
authorization: 'ApiKey [REDACTED]'
29+
```
30+
31+
The OTLP endpoint can be any OTel/EDOT collector. It is recommended to use the mOTLP (Managed OTLP) endpoint that is provided by Elastic Cloud. The instructions to retrieve the OTLP endpoint and the API Key are available in [Get started with traces and APM](https://www.elastic.co/docs/solutions/observability/apm/get-started).
32+
33+
### Supported exporter protocols
34+
35+
{{kib}} supports gRPC, protobuf and plain HTTP protocols to export the OTel Traces. The protocol to use is specified in the config via top property name in the exporter's declaration. The config syntax is the same for all.
36+
37+
```yaml
38+
telemetry.tracing:
39+
enabled: true
40+
sample_rate: 1 # 1 by default
41+
exporters:
42+
- grpc:
43+
url: <URL_TO_THE_GRPC_OTLP_ENDPOINT>
44+
headers:
45+
authorization: 'ApiKey [REDACTED]'
46+
- proto:
47+
url: <URL_TO_THE_PROTO_OTLP_ENDPOINT>
48+
headers:
49+
authorization: 'ApiKey [REDACTED]'
50+
- http:
51+
url: <URL_TO_THE_HTTP_OTLP_ENDPOINT>
52+
headers:
53+
authorization: 'ApiKey [REDACTED]'
54+
```
55+
56+
:::::{tip}
57+
gRPC typically operates on a different port to the protobuf and http protocols.
58+
59+
When using the mOTLP endpoint, the port is the same, but the endpoint changes:
60+
61+
- gRPC uses the root path (https://my-ech-deployment.ingest.europe-west1.gcp.elastic-cloud.com:443)
62+
- Protobuf and HTTP use the path `/v1/traces` (https://my-ech-deployment.ingest.europe-west1.gcp.elastic-cloud.com:443/v1/traces)
63+
:::::
64+
65+
### Enable OTel Traces on the server + Elastic RUM on the browser in {{kib}}
66+
67+
:::::{important}
68+
OTel instrumentation is only available on the server side. For RUM observability, {{kib}} uses [Elastic RUM](https://www.elastic.co/docs/solutions/observability/apm/apm-agents/real-user-monitoring-rum).
69+
70+
OTel instrumentation in the browser will be available in the future, once the [OTel for RUM](https://www.elastic.co/docs/solutions/observability/applications/otel-rum) is ready for production.
71+
:::::
72+
73+
When `telemetry.tracing.enabled` is `true`, server-side Elastic APM is disabled by default, but the `kibana-frontend` (RUM) service remains active. Elastic APM and OpenTelemetry tracing cannot be enabled simultaneously; setting `elastic.apm.active: true` while OTel tracing is enabled causes Kibana to fail on startup. You can still collect browser traces with Elastic RUM.
74+
75+
To enable Elastic RUM alongside OTel tracing, define the APM Server's URL in the Kibana config. [Any settings accepted by the agent](https://www.elastic.co/docs/reference/apm/agents/rum-js/configuration) are also accepted:
76+
77+
```yaml
78+
elastic:
79+
apm:
80+
serverUrl: https://my-ech-deployment.apm.europe-west1.gcp.cloud.es.io:443
81+
# RUM is enabled by default when telemetry.tracing.enabled is true; serverUrl is required to send data to your deployment.
82+
# Below are optional
83+
environment: localhost
84+
transactionSampleRate: 1
85+
```
86+
87+
:::::{tip}
88+
RUM sends traces from the browser without embedded credentials. Prefer an Elastic Cloud Hosted (ECH) APM endpoint configured for RUM intake. Serverless APM endpoints often require authenticated intake and are usually not suitable for RUM unless your deployment explicitly supports unauthenticated browser intake.
89+
:::::
1590

1691
## Instrumenting with Elastic APM [_instrumenting_with_elastic_apm]
1792

93+
:::::{warning}
94+
This approach is deprecated. Use [OTel Traces](#_instrumenting_with_otel_traces) instead.
95+
:::::
96+
1897
{{kib}} ships with the [Elastic APM Node.js Agent](https://github.com/elastic/apm-agent-nodejs) built-in for debugging purposes.
1998

20-
With an application as varied and complex as Kibana has become, it’s not practical or scalable to craft all possible performance measurements by hand ahead of time. As such, we need to rely on tooling to help us catch things we may otherwise have missed.
99+
With an application as varied and complex as Kibana has become, it’s not practical or scalable to craft all possible performance measurements by hand ahead of time. As such, we need to rely on tooling to help us catch things we might otherwise have missed.
21100

22-
For example, say you implement a brand new feature, plugin or service but don’t quite know how it will impact Kibana’s performance as a whole. APM allows us to not only spot that something is slow, but also hints at why it might be performing slowly. For example, if a function is slow on specific types of inputs, we can see where the time is spent by viewing the trace for that function call in the APM UI.
101+
For example, say you implement a brand new feature, plugin or service but do not know how it will impact Kibana’s performance as a whole. APM allows us to not only spot that something is slow, but also hints at why it might be performing slowly. For example, if a function is slow on specific types of inputs, we can see where the time is spent by viewing the trace for that function call in the APM UI.
23102

24103
![apm example trace](images/apm_example_trace.png)
25104

@@ -47,57 +126,56 @@ APM [Real User Monitoring agent](apm-agent-rum-js://reference/index.md) is not a
47126
ELASTIC_APM_ACTIVE=true yarn start
48127
// activates both Node.js and RUM agent
49128
```
50-
Once the agent is active, it will trace all incoming HTTP requests to {{kib}}, monitor for errors, and collect process-level metrics. The collected data will be sent to the APM Server and is viewable in the APM UI in {{kib}}.
51129
130+
Once the agent is active, it will trace all incoming HTTP requests to {{kib}}, monitor for errors, and collect process-level metrics. The collected data will be sent to the APM Server and is viewable in the APM UI in {{kib}}.
52131
53132
## Running Kibana with the APM Agent Locally [_running_kibana_with_the_apm_agent_locally]
54133
55134
The easiest and recommended way of running Kibana with the APM agent locally is to use the solution provided by the [apm-integration-testing](https://github.com/elastic/apm-integration-testing) repo. You’ll need [Docker](https://www.docker.com/community-edition), [Docker Compose](https://docs.docker.com/compose/install/) and [Python (version 3 preferred)](https://www.python.org/downloads) to use the tool.
56135
57-
58136
### Quick start guide [_quick_start_guide]
59137
60138
1. Clone the [elastic/apm-integration-testing](https://github.com/elastic/apm-integration-testing) repo.
61139
2. Change into the apm-integration-testing repo:
62140
63-
```bash
64-
cd apm-integration-testing
65-
```
141+
```bash
142+
cd apm-integration-testing
143+
```
66144

67145
3. Run {{es}} and the APM servers without running Kibana:
68146

69-
```bash
70-
./scripts/compose.py start master --no-kibana
71-
```
147+
```bash
148+
./scripts/compose.py start master --no-kibana
149+
```
72150

73151
4. Clone the [elastic/kibana](https://github.com/elastic/kibana) repo.
74152
5. Change into the {{kib}} repo:
75153

76-
```bash
77-
cd ../kibana
78-
```
154+
```bash
155+
cd ../kibana
156+
```
79157

80158
6. Change the elasticsearch credentials in your `kibana.yml` configuration file to match those needed by elasticsearch and the APM server (see the apm-integration-testing repo’s [README](https://github.com/elastic/apm-integration-testing#logging-in) for users provided to test different scenarios).
81159
7. Make sure that the APM agent is active and points to the local APM server by adding the following configuration settings to a config file under `config/kibana.dev.yml`:
82160

83-
Example `config/kibana.dev.yml` file:
161+
Example `config/kibana.dev.yml` file:
84162

85-
```yaml
86-
elastic:
87-
apm:
88-
active: true
89-
serverUrl: http://localhost:8200
90-
secretToken: very_secret
91-
centralConfig: true
92-
breakdownMetrics: true
93-
transactionSampleRate: 0.1
94-
```
163+
```yaml
164+
elastic:
165+
apm:
166+
active: true
167+
serverUrl: http://localhost:8200
168+
secretToken: very_secret
169+
centralConfig: true
170+
breakdownMetrics: true
171+
transactionSampleRate: 0.1
172+
```
95173
96174
8. Start Kibana with APM active using:
97175
98-
```bash
99-
yarn start
100-
```
176+
```bash
177+
yarn start
178+
```
101179

102180
9. After Kibana starts up, navigate to the APM app, where you should see some transactions.
103181

@@ -108,4 +186,3 @@ You can now continue doing what you want to in Kibana (e.g. install sample data
108186
```bash
109187
./scripts/compose.py stop
110188
```
111-

src/platform/packages/private/kbn-apm-config-loader/src/config.test.ts

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
} from './config.test.mocks';
1818

1919
import { ApmConfiguration, CENTRALIZED_SERVICE_BASE_CONFIG } from './config';
20+
import { shouldInstrumentClient } from './rum_agent_configuration';
2021

2122
describe('ApmConfiguration', () => {
2223
beforeEach(() => {
@@ -222,13 +223,10 @@ describe('ApmConfiguration', () => {
222223
it('ELASTIC_APM_KIBANA_FRONTEND_ACTIVE', () => {
223224
process.env.ELASTIC_APM_KIBANA_FRONTEND_ACTIVE = 'false';
224225
const config = new ApmConfiguration(mockedRootDir, {}, false);
225-
const serverConfig = config.getConfig('servicesOverrides');
226-
// @ts-ignore
227-
expect(serverConfig.servicesOverrides).toEqual({
228-
'kibana-frontend': {
229-
active: false,
230-
},
231-
});
226+
const frontendConfig = config.getConfig('kibana-frontend');
227+
expect(frontendConfig.active).toBe(false);
228+
expect(frontendConfig).not.toHaveProperty('servicesOverrides');
229+
expect(shouldInstrumentClient(frontendConfig)).toBe(false);
232230
});
233231

234232
it('does not override the environment from NODE_ENV if already set in the config file', () => {
@@ -476,4 +474,67 @@ describe('ApmConfiguration', () => {
476474
expect(config.isUsersRedactionEnabled()).toEqual(false);
477475
});
478476
});
477+
478+
describe('OTel tracing affects the default config', () => {
479+
let config: ApmConfiguration;
480+
const kibanaConfig = {
481+
telemetry: {
482+
enabled: true,
483+
tracing: {
484+
enabled: true,
485+
sample_rate: 1,
486+
exporters: [],
487+
},
488+
},
489+
};
490+
491+
beforeAll(() => {
492+
config = new ApmConfiguration(mockedRootDir, kibanaConfig, false);
493+
});
494+
495+
it('sets "active: false" for the server service', () => {
496+
const serverConfig = config.getConfig('serviceName');
497+
expect(serverConfig.active).toBe(false);
498+
expect(serverConfig).not.toHaveProperty('servicesOverrides');
499+
});
500+
501+
it('sets "active: true" for the "kibana-frontend" service', () => {
502+
const frontendConfig = config.getConfig('kibana-frontend');
503+
expect(frontendConfig.active).toBe(true);
504+
expect(frontendConfig).not.toHaveProperty('servicesOverrides');
505+
expect(shouldInstrumentClient(frontendConfig)).toBe(true);
506+
});
507+
508+
it('disables kibana-frontend when ELASTIC_APM_KIBANA_FRONTEND_ACTIVE=false', () => {
509+
process.env.ELASTIC_APM_KIBANA_FRONTEND_ACTIVE = 'false';
510+
const configWithEnv = new ApmConfiguration(mockedRootDir, kibanaConfig, false);
511+
const frontendConfig = configWithEnv.getConfig('kibana-frontend');
512+
expect(frontendConfig.active).toBe(false);
513+
expect(frontendConfig).not.toHaveProperty('servicesOverrides');
514+
expect(shouldInstrumentClient(frontendConfig)).toBe(false);
515+
});
516+
517+
it('disables kibana-frontend when overridden in elastic.apm.servicesOverrides', () => {
518+
const configWithYamlOverride = new ApmConfiguration(
519+
mockedRootDir,
520+
{
521+
...kibanaConfig,
522+
elastic: {
523+
apm: {
524+
servicesOverrides: {
525+
'kibana-frontend': {
526+
active: false,
527+
},
528+
},
529+
},
530+
},
531+
},
532+
false
533+
);
534+
const frontendConfig = configWithYamlOverride.getConfig('kibana-frontend');
535+
expect(frontendConfig.active).toBe(false);
536+
expect(frontendConfig).not.toHaveProperty('servicesOverrides');
537+
expect(shouldInstrumentClient(frontendConfig)).toBe(false);
538+
});
539+
});
479540
});

src/platform/packages/private/kbn-apm-config-loader/src/config.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,12 @@ interface KibanaRawConfig {
6767
};
6868
}
6969

70+
type ApmBaseConfiguration = AgentConfigOptions & {
71+
servicesOverrides?: Record<string, AgentConfigOptions>;
72+
};
73+
7074
export class ApmConfiguration {
71-
private baseConfig?: AgentConfigOptions;
75+
private baseConfig?: ApmBaseConfiguration;
7276
private kibanaVersion: string;
7377
private pkgBuild: Record<string, any>;
7478

@@ -92,12 +96,17 @@ export class ApmConfiguration {
9296
serviceName,
9397
};
9498

95-
const serviceOverride = servicesOverrides[serviceName];
99+
const serviceOverride = merge(
100+
{},
101+
baseConfig.servicesOverrides?.[serviceName],
102+
servicesOverrides[serviceName]
103+
);
96104
if (serviceOverride) {
97105
baseConfig = merge({}, baseConfig, serviceOverride);
98106
}
99107

100-
return baseConfig;
108+
const { servicesOverrides: _servicesOverrides, ...resolvedConfig } = baseConfig;
109+
return resolvedConfig;
101110
}
102111

103112
public getTelemetryConfig(): TelemetryConfig {
@@ -123,6 +132,7 @@ export class ApmConfiguration {
123132
serviceVersion: this.kibanaVersion,
124133
},
125134
DEFAULT_CONFIG,
135+
this.getElasticAPMConfigDerivedFromOTelConfig(),
126136
this.getUuidConfig(),
127137
this.getGitConfig(),
128138
this.getCiConfig(),
@@ -158,6 +168,32 @@ export class ApmConfiguration {
158168
return this.baseConfig;
159169
}
160170

171+
/**
172+
* Retrieve the default Elastic APM config derived from the OTel config.
173+
* Only applies when `telemetry.tracing.enabled` is true; otherwise returns an empty object.
174+
*
175+
* @returns The default Elastic APM config derived from the OTel config.
176+
*/
177+
private getElasticAPMConfigDerivedFromOTelConfig(): ApmBaseConfiguration {
178+
const telemetryConfig = this.getTelemetryConfig();
179+
if (telemetryConfig.tracing.enabled) {
180+
// We want to disable Elastic APM if OTel tracing is enabled.
181+
// Note that this is only used for calculating our default config. The user can still override these.
182+
return {
183+
active: false,
184+
contextPropagationOnly: false,
185+
servicesOverrides: {
186+
// Keep RUM active by default
187+
'kibana-frontend': {
188+
active: true,
189+
},
190+
},
191+
};
192+
}
193+
194+
return {};
195+
}
196+
161197
/**
162198
* Override some config values when specific environment variables are used
163199
*/

0 commit comments

Comments
 (0)