Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 95 additions & 69 deletions solutions/observability/applications/otel-rum.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,37 @@ Avoid using OpenTelemetry alongside any other {{apm-agent}}, including Elastic {

### OTLP endpoint

You have two main options for setting up an OTLP endpoint:
You need an OTLP Collector to ingest data from the OpenTelemetry RUM instrumentation. If you're setting up a new deployment, you can create an {{ecloud}} hosted deployment or {{serverless-short}} project, which includes the [{{motlp}}](opentelemetry://reference/motlp.md).

1. Use an existing OpenTelemetry Collector: If you already have a Collector deployed in your infrastructure, you can configure it to accept telemetry from browsers. This requires configuring CORS headers either directly on the Collector (if it's publicly accessible) or through a reverse proxy.
Depeding on where the collector is placed in your infrastructure you might have two setup options:

2. **Start from scratch with {{ecloud}}**: If you're setting up a new deployment, you can create an {{ecloud}} hosted deployment or {{serverless-short}} project, which includes the [{{motlp}}](opentelemetry://reference/motlp.md). This approach requires a reverse proxy to handle CORS configuration.
1. Reverse proxy (recommended): Take this approach if you're using {{motlp}} or if your collector is not publicly available. Refer to the next section for further information.

#### Use an existing OpenTelemetry Collector [use-an-existing-open-telemetry-collector]

If you already have an OpenTelemetry Collector in your infrastructure, you can reuse it to ingest the traces, metrics, and logs generated by your instrumented web applications.
2. Setup Cross-Origin Resource Sharing (CORS): You can opt in for this setup if your collector is public and you can modify its configuration.

::::{tab-set}

:::{tab-item} Reverse proxy (recommended)

If your Collector is not publicly available or you want to control where the data is coming from, use a reverse proxy to forward data from the browsers through your web application. This is the recommended method.
Use a reverse proxy to redirect the requests from your web app to the collector for these reasons:

- There is no option in {{motlp}} to configure [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS) and without the proper configuration browsers can't send data to it.
- Don't expose API keys or other authentication tokens in your web app, because they would be visible. Append the proper `Authorization` header in the proxied request to keep them valid and at the same time not leaking any secret to the public.
- You can apply rate limiting or any other mechanisms to control traffic before it reaches the collector.

:::{dropdown} Example NGINX reverse proxy configuration

The following snippet shows the configuration for an NGINX reverse proxy to forward all telemetry to the Collector located at `collector.example.com` from the origin `webapp.example.com`:

```nginx
server {
listen 80 default_server;
server_name _;
# Configuration for HTTP/HTTPS goes here
location / {
# Take care of preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Access-Control-Allow-Origin' 'webapp.example.com' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Content-Language,Content-Type' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Authorization,Content-Language,Content-Type' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
Expand All @@ -68,92 +69,117 @@ server {

add_header 'Access-Control-Allow-Origin' 'webapp.example.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Content-Language,Content-Type' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Authorization,Content-Language,Content-Type' always;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

# Set the auth and proxy the request
proxy_set_header Authorization 'ApiKey ...your Elastic API key...';
proxy_pass https://collector.example.com:4318;
}
}
```

:::
:::

:::{tab-item} Public Collector with CORS
:::{tab-item} Configure Collector for CORS

If the collector is publicly available, you can send the telemetry data directly to it. Your collector must be available under a domain name, for example `collector.example.com:4318`, 4318 being the default port for the OTLP HTTP/JSON protocol). Your web application sends data from its own origin `webapp.example.com` to a different one, and [Cross-Origin Resource Sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS) (CORS) should be configured so browsers allow sending data to a different origin.

Take these aspects into consideration:

If the Collector is publicly available, you can send the telemetry data directly to it. Your Collector should be available under a domain name, for example `collector.example.com:4318` (4318 is the default port for the OTLP HTTP/JSON protocol). Your web application should send data from its own origin `webapp.example.com` to a different one, and [Cross-Origin Resource Sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS) (CORS) should be configured so browsers allow sending data to a different origin.
- Every time you add a new application, you need to update the CORS configuration to add the new origin. Using a wildcard value like `https://*` is discouraged because you are allowing any website to be able to send data to the collector. A more convenient configuration is to have a wildcard per subdomains like `https://*.example.com`.
- Your collector requires an authorization header and the OpenTelemetry instrumentation is sending data directly to it. This means you should add the required header with the API key value in the instrumentation script. This script is visible to anyone that has access to the app.

To configure CORS in your collector, change the configuration in your HTTP receiver:
This is a basic EDOT Collector configuration file that activates CORS:

```yaml
receivers:
# Receives data from other Collectors in Agent mode
# Receives data from other Collectors in Agent mode or OTEL SDKs
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317 # Listen on all interfaces
endpoint: 0.0.0.0:4317 # Listen on all interfaces
auth:
authenticator: apikeyauth
http:
endpoint: 0.0.0.0:4318 # Listen on all interfaces
# Configure CORS for RUM
endpoint: 0.0.0.0:4318 # Listen on all interfaces
auth:
authenticator: apikeyauth
# configure CORS for RUM
# ref: https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/confighttp/README.md#server-configuration
cors:
allowed_origins:
- http://webapp.example.com
- https://webapp.example.com
- http://*.example.com
- https://*.example.com
connectors:
elasticapm: {} # Elastic APM Connector

processors:
batch:
send_batch_size: 1000
timeout: 1s
send_batch_max_size: 1500
batch/metrics:
send_batch_max_size: 0 # Explicitly set to 0 to avoid splitting metrics requests
timeout: 1s
elastictrace: {} # Elastic Trace Processor

exporters:
debug: {}
elasticsearch/otel:
endpoints:
- http://elasticsearch:9200
user: elastic
password: ${ES_LOCAL_PASSWORD}
tls:
insecure_skip_verify: true
mapping:
mode: otel

service:
pipelines:
metrics:
receivers: [otlp]
processors: [batch/metrics]
exporters: [debug, elasticsearch/otel]
logs:
receivers: [otlp]
processors: [batch]
exporters: [debug, elasticapm, elasticsearch/otel]
traces:
receivers: [otlp]
processors: [batch, elastictrace]
exporters: [debug, elasticapm, elasticsearch/otel]
metrics/aggregated-otel-metrics:
receivers:
- elasticapm
processors: [] # No processors defined in the original for this pipeline
exporters:
- debug
- elasticsearch/otel
extensions: [apikeyauth] # Enable auth extension

extensions:
# Auth via Elastic API key
# ref: https://www.elastic.co/docs/reference/edot-collector/config/authentication-methods
apikeyauth:
endpoint: "http://elasticsearch:9200"
application_privileges:
- application: "apm"
privileges: ["config_agent:read"]
resources: ["*"]
cache:
capacity: 1000
ttl: "5m"
pbkdf2_iterations: 10000
key_headers: []
```

For details on the configuration, refer to the [OpenTelemetry Collector HTTP server configuration](https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/confighttp/README.md#server-configuration).

:::
::::

#### Start with {{ecloud}}

If you're new to {{observability}} or want to start from scratch, create a new {{ecloud}} hosted deployment (ECH) or a {{serverless-short}} project:

- To create a new ECH deployment, follow the guidelines in [Deploy and manage Elastic Cloud hosted](/deploy-manage/deploy/elastic-cloud/cloud-hosted.md).
- To create a {{serverless-short}} project, follow the guidelines in [Get started with Elastic Observability](/solutions/observability/get-started.md).

Both options come with a [Managed OTLP Endpoint (mOTLP)](opentelemetry://reference/motlp.md). However, the mOTLP endpoint cannot be configured for CORS.

:::{dropdown} Example NGINX reverse proxy configuration for mOTLP

The following snippet shows the configuration for an NGINX reverse proxy to forward all telemetry to the mOTLP endpoint from the origin `webapp.example.com`:

```nginx
server {
listen 80 default_server;
server_name _;
location / {
# Take care of preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Access-Control-Allow-Origin' 'webapp.example.com' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Content-Language,Content-Type,Authorization' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}

add_header 'Access-Control-Allow-Origin' 'webapp.example.com' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Accept-Language,Content-Language,Content-Type,Authorization' always;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Authorization $http_authorization;

proxy_pass https://<motlp-endpoint>:443;
}
}
```

:::

## Installation

OpenTelemetry packages for web instrumentation are published to npm. You can install them with the package manager of your choice.
Expand Down