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

Be able to correlate timeouts in reverse-proxy layer in front of Synapse (pull request ID from header) #13801

6 changes: 6 additions & 0 deletions docs/usage/configuration/config_documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,12 @@ Sub-options for each listener include:
* `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
behind a reverse-proxy.

* `request_id_header`: The header used as the basis for the request ID which
is used in logs and tracing to correlate requests. Useful when Synapse is
behind a reverse-proxy. For example, if you use Cloudflare in front of
Synapse, you can set this to `"cf-ray"` to match up requests even when the
Cloudflare layer times out before Synapse is done.

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

Expand Down
4 changes: 3 additions & 1 deletion synapse/config/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ class HttpListenerConfig:
resources: List[HttpResourceConfig] = attr.Factory(list)
additional_resources: Dict[str, dict] = attr.Factory(dict)
tag: Optional[str] = None
request_id_header: Optional[str] = None


@attr.s(slots=True, frozen=True, auto_attribs=True)
Expand Down Expand Up @@ -887,7 +888,7 @@ def read_gc_thresholds(
)


def parse_listener_def(num: int, listener: Any) -> ListenerConfig:
def parse_listener_def(num: int, listener: JsonDict) -> ListenerConfig:
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
"""parse a listener config from the config file"""
listener_type = listener["type"]
# Raise a helpful error if direct TCP replication is still configured.
Expand Down Expand Up @@ -928,6 +929,7 @@ def parse_listener_def(num: int, listener: Any) -> ListenerConfig:
resources=resources,
additional_resources=listener.get("additional_resources", {}),
tag=listener.get("tag"),
request_id_header=listener.get("request_id_header"),
MadLittleMods marked this conversation as resolved.
Show resolved Hide resolved
)

return ListenerConfig(port, bind_addresses, listener_type, tls, http_config)
Expand Down
11 changes: 10 additions & 1 deletion synapse/http/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,12 @@ def __init__(
site: "SynapseSite",
*args: Any,
max_request_body_size: int = 1024,
request_id_header: Optional[str],
**kw: Any,
):
super().__init__(channel, *args, **kw)
self._max_request_body_size = max_request_body_size
self.request_id_header = request_id_header
self.synapse_site = site
self.reactor = site.reactor
self._channel = channel # this is used by the tests
Expand Down Expand Up @@ -172,7 +174,13 @@ def set_opentracing_span(self, span: "opentracing.Span") -> None:
self._opentracing_span = span

def get_request_id(self) -> str:
return "%s-%i" % (self.get_method(), self.request_seq)
if self.request_id_header:
request_id_value = self.getHeader(self.request_id_header)

if not request_id_value:
request_id_value = self.request_seq

return "%s-%i" % (self.get_method(), request_id_value)

def get_redacted_uri(self) -> str:
"""Gets the redacted URI associated with the request (or placeholder if the URI
Expand Down Expand Up @@ -617,6 +625,7 @@ def request_factory(channel: HTTPChannel, queued: bool) -> Request:
self,
max_request_body_size=max_request_body_size,
queued=queued,
request_id_header=config.http_options.request_id_header,
)

self.requestFactory = request_factory # type: ignore
Expand Down