Log Streaming
These instructions primarily apply to self-hosted users. To set up log streaming on the Medplum Hosted instance, please reach out to info@medplum.com
Medplum can be configured to stream service logs to your existing log management tools, like SumoLogic, DataDog, or Splunk. Centralizing log management allows for better observability and auditability, and offers real-time analytics capabilities.
Medplum Logs
Medplum server can stream the following to STDOUT
- Login Attempts
- Other troubleshooting information
- All RESTful interactions with FHIR resources, which are recorded as FHIR AuditEvent resources
To capture AuditEvent resources for any RESTful interactions you must set the server configuration for logAuditEvents
For batch requests and GraphQL queries, each individual read/search operation executed by the query generates its own log line. While these operations are logged separately, they all share the same request ID / trace ID for easy correlation and tracing.
Forwarding Logs via AWS Lambda
To forward logs from CloudWatch to external platforms, AWS Lambda functions are utilized. This involves creating Lambda functions that are triggered by new log entries in CloudWatch and are configured to push these logs to the chosen external logging system.
- For SumoLogic: Setup Guide
- For DataDog: Setup Guide
- For Splunk: Setup Guide
Log Correlation
Medplum includes request IDs and trace IDs to aid in log correlation, enhancing debugging and monitoring capabilities, and accepts a caller-supplied log tag for correlating against your own records.
Request IDs
The request ID is always generated by the Medplum server, and is never taken from the caller. A caller-controlled request ID cannot be relied upon during an incident investigation, because a caller can collide, reuse, or forge it.
Every response includes the server-generated request ID in the X-Request-Id header, along with the trace ID in X-Trace-Id. Log these values on your side to correlate your logs with Medplum's.
Trace IDs
Clients can pass in their own trace ID. Medplum accepts, in order of precedence:
traceparent, the W3C Trace Context standard, which is what OpenTelemetry SDKs emit. This is the recommended header.X-Trace-Id, for callers that do not implement trace context.X-Amzn-Trace-Id, set by AWS load balancers.
Values that represent a 128 bit trace ID are normalized to canonical W3C form, which is 32 lowercase hex characters. A traceparent contributes its trace ID field, and UUIDs and X-Ray trace IDs are converted, so that every representation of the same trace normalizes to the same value. Other values are preserved as given.
A trace ID must be at most 64 characters of letters, digits, -, and .. Medplum generates a trace ID when the request does not carry a valid one.
When Medplum makes an outbound request on behalf of a request, such as invoking a bot or delivering a subscription, it sends X-Trace-Id, and a well-formed traceparent with a new span ID whenever the trace ID is a W3C trace ID.
A trace ID that is not a 128 bit value, such as a ULID or a Datadog decimal ID, cannot be expressed as a traceparent. Medplum sends X-Trace-Id alone in that case rather than emitting a malformed header, so W3C trace context propagation stops at Medplum for those callers. Send traceparent if you need the trace to continue downstream in W3C form.
Example: Adding a trace id to a medplum GET request
- Typescript
- cURL
await medplum.readResource('Patient', 'homer-simpson', {
headers: {
'X-TRACE-ID': 'MY-TRACE-ID',
},
});
curl https://api.medplum.com/fhir/R4/Patient/homer-simpson \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/fhir+json" \
-H "X-TRACE-ID: "MY-TRACE-ID
Log Tags
Trace IDs correlate a request across systems. When you instead need to attach your own piece of
metadata to a request, send the X-Medplum-Log-Tag header. Its value is copied verbatim onto
the logTag field of every log line emitted through the request logger while serving that
request, including the Request served access log line.
The most common use is per-user traceability. When a server side application authenticates as a
single machine-to-machine ClientApplication, every
request arrives under the same Medplum identity. Passing your own end user identifier in
X-Medplum-Log-Tag lets you answer "which of my users caused this request?" from the logs.
Example: Tagging a request with your own end user identifier
- Typescript
- cURL
await medplum.readResource('Patient', 'homer-simpson', {
headers: {
'X-Medplum-Log-Tag': 'my-end-user-1234',
},
});
curl https://api.medplum.com/fhir/R4/Patient/homer-simpson \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/fhir+json" \
-H "X-Medplum-Log-Tag: my-end-user-1234"
Note the following about this header:
- The value is opaque to Medplum. It is never parsed, resolved to a Medplum resource, or used to
make an authorization decision. If you need the acting user to affect authorship and access
control, use On-Behalf-Of instead, which resolves to a real
ProjectMembership. - The value must be 1 to 128 characters of printable ASCII. Encode values outside that range, for
example as base64. A request carrying a value that does not meet these constraints is rejected
with a
400 Bad Request, rather than served with the value dropped. You set this header so the value is in the logs later, so a silent drop would hide the mistake until someone went looking for data that was never recorded. Correct the value or omit the header. - The value is not propagated. It appears on log lines for the synchronous request only; background
work triggered by the request, such as an async batch, a subscription delivery, or a bot
execution, does not carry it, and it is not forwarded on outbound requests the way
X-Trace-Idis. - The value is not recorded on AuditEvent resources, and so
does not appear on the log lines produced by
logAuditEvents. Correlate anAuditEventwith alogTagthrough the request ID and trace ID that both carry. - The header only has an effect on requests that produce log output. A request that emits no log
lines has nothing to annotate, so enable
logRequeststo get one access log line per request.
Log output is retained by your log management tooling and is not subject to FHIR access controls.
Do not put PHI or other sensitive data in X-Medplum-Log-Tag. Use an opaque identifier that
you can resolve against your own records.