Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 5093cbf

Browse files
Be able to correlate timeouts in reverse-proxy layer in front of Synapse (pull request ID from header) (#13801)
Fix #13685 New config: ```diff listeners: - port: 8008 tls: false type: http x_forwarded: true + request_id_header: "cf-ray" bind_addresses: ['::1', '127.0.0.1', '0.0.0.0'] ```
1 parent 140af0c commit 5093cbf

File tree

5 files changed

+38
-5
lines changed

5 files changed

+38
-5
lines changed

changelog.d/13801.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add `listeners[x].request_id_header` config to specify which request header to extract and use as the request ID in order to correlate requests from a reverse-proxy.

docs/reverse_proxy.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ listens to traffic on localhost. (Do not change `bind_addresses` to `127.0.0.1`
4545
when using a containerized Synapse, as that will prevent it from responding
4646
to proxied traffic.)
4747

48+
Optionally, you can also set
49+
[`request_id_header`](../usage/configuration/config_documentation.md#listeners)
50+
so that the server extracts and re-uses the same request ID format that the
51+
reverse proxy is using.
4852

4953
## Reverse-proxy configuration examples
5054

docs/usage/configuration/config_documentation.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,16 @@ Sub-options for each listener include:
434434
* `tls`: set to true to enable TLS for this listener. Will use the TLS key/cert specified in tls_private_key_path / tls_certificate_path.
435435

436436
* `x_forwarded`: Only valid for an 'http' listener. Set to true to use the X-Forwarded-For header as the client IP. Useful when Synapse is
437-
behind a reverse-proxy.
437+
behind a [reverse-proxy](../../reverse_proxy.md).
438+
439+
* `request_id_header`: The header extracted from each incoming request that is
440+
used as the basis for the request ID. The request ID is used in
441+
[logs](../administration/request_log.md#request-log-format) and tracing to
442+
correlate and match up requests. When unset, Synapse will automatically
443+
generate sequential request IDs. This option is useful when Synapse is behind
444+
a [reverse-proxy](../../reverse_proxy.md).
445+
446+
_Added in Synapse 1.68.0._
438447

439448
* `resources`: Only valid for an 'http' listener. A list of resources to host
440449
on this port. Sub-options for each resource are:

synapse/config/server.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ class HttpListenerConfig:
206206
resources: List[HttpResourceConfig] = attr.Factory(list)
207207
additional_resources: Dict[str, dict] = attr.Factory(dict)
208208
tag: Optional[str] = None
209+
request_id_header: Optional[str] = None
209210

210211

211212
@attr.s(slots=True, frozen=True, auto_attribs=True)
@@ -520,9 +521,11 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
520521
):
521522
raise ConfigError("allowed_avatar_mimetypes must be a list")
522523

523-
self.listeners = [
524-
parse_listener_def(i, x) for i, x in enumerate(config.get("listeners", []))
525-
]
524+
listeners = config.get("listeners", [])
525+
if not isinstance(listeners, list):
526+
raise ConfigError("Expected a list", ("listeners",))
527+
528+
self.listeners = [parse_listener_def(i, x) for i, x in enumerate(listeners)]
526529

527530
# no_tls is not really supported any more, but let's grandfather it in
528531
# here.
@@ -889,6 +892,9 @@ def read_gc_thresholds(
889892

890893
def parse_listener_def(num: int, listener: Any) -> ListenerConfig:
891894
"""parse a listener config from the config file"""
895+
if not isinstance(listener, dict):
896+
raise ConfigError("Expected a dictionary", ("listeners", str(num)))
897+
892898
listener_type = listener["type"]
893899
# Raise a helpful error if direct TCP replication is still configured.
894900
if listener_type == "replication":
@@ -928,6 +934,7 @@ def parse_listener_def(num: int, listener: Any) -> ListenerConfig:
928934
resources=resources,
929935
additional_resources=listener.get("additional_resources", {}),
930936
tag=listener.get("tag"),
937+
request_id_header=listener.get("request_id_header"),
931938
)
932939

933940
return ListenerConfig(port, bind_addresses, listener_type, tls, http_config)

synapse/http/site.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,12 @@ def __init__(
7272
site: "SynapseSite",
7373
*args: Any,
7474
max_request_body_size: int = 1024,
75+
request_id_header: Optional[str] = None,
7576
**kw: Any,
7677
):
7778
super().__init__(channel, *args, **kw)
7879
self._max_request_body_size = max_request_body_size
80+
self.request_id_header = request_id_header
7981
self.synapse_site = site
8082
self.reactor = site.reactor
8183
self._channel = channel # this is used by the tests
@@ -172,7 +174,14 @@ def set_opentracing_span(self, span: "opentracing.Span") -> None:
172174
self._opentracing_span = span
173175

174176
def get_request_id(self) -> str:
175-
return "%s-%i" % (self.get_method(), self.request_seq)
177+
request_id_value = None
178+
if self.request_id_header:
179+
request_id_value = self.getHeader(self.request_id_header)
180+
181+
if request_id_value is None:
182+
request_id_value = str(self.request_seq)
183+
184+
return "%s-%s" % (self.get_method(), request_id_value)
176185

177186
def get_redacted_uri(self) -> str:
178187
"""Gets the redacted URI associated with the request (or placeholder if the URI
@@ -611,12 +620,15 @@ def __init__(
611620
proxied = config.http_options.x_forwarded
612621
request_class = XForwardedForRequest if proxied else SynapseRequest
613622

623+
request_id_header = config.http_options.request_id_header
624+
614625
def request_factory(channel: HTTPChannel, queued: bool) -> Request:
615626
return request_class(
616627
channel,
617628
self,
618629
max_request_body_size=max_request_body_size,
619630
queued=queued,
631+
request_id_header=request_id_header,
620632
)
621633

622634
self.requestFactory = request_factory # type: ignore

0 commit comments

Comments
 (0)