From 9e87ed76a79ae889ae5b3c500748b0e0dc659104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Steinkopf=20S=C3=B8hoel?= Date: Wed, 18 Dec 2024 14:38:41 +0100 Subject: [PATCH] Pass ert trace context to dark storage --- src/ert/services/_storage_main.py | 21 +++++++++++---------- src/ert/services/storage_service.py | 5 +++++ src/ert/shared/storage/command.py | 6 ++++++ src/ert/trace.py | 7 +++++++ 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/ert/services/_storage_main.py b/src/ert/services/_storage_main.py index b21d56022fc..21b03f37955 100644 --- a/src/ert/services/_storage_main.py +++ b/src/ert/services/_storage_main.py @@ -22,8 +22,9 @@ from ert.shared import __file__ as ert_shared_path from ert.shared import find_available_socket from ert.shared.storage.command import add_parser_options -from ert.trace import get_trace_id, trace, tracer, tracer_provider +from ert.trace import tracer, tracer_provider +from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator from opentelemetry.trace.span import Span DARK_STORAGE_APP = "ert.dark_storage.app:app" @@ -87,7 +88,6 @@ def _create_connection_info(sock: socket.socket, authtoken: str) -> dict[str, An return connection_info def run_server(args: argparse.Namespace | None = None, debug: bool = False, uvicorn_config = None) -> None: - trace_id = get_trace_id() if args is None: args = parse_args() @@ -112,8 +112,8 @@ def run_server(args: argparse.Namespace | None = None, debug: bool = False, uvic server = Server(config, json.dumps(connection_info)) logger = logging.getLogger("ert.shared.storage.info") - log_level = logging.INFO if args.verbose else logging.WARNING - logger.setLevel(log_level) + if args.verbose and logger.level > logging.INFO: + logger.setLevel(logging.INFO) logger.info("Storage server is ready to accept requests. Listening on:") for url in connection_info["urls"]: logger.info(f" {url}") @@ -162,27 +162,28 @@ def main(): config_args.update(reload=True, reload_dirs=[os.path.dirname(ert_shared_path)]) uvicorn_config = uvicorn.Config(DARK_STORAGE_APP, **config_args) # Need to run uvicorn.Config before entering the ErtPluginContext because uvicorn.Config overrides the configuration of existing loggers, thus removing log handlers added by ErtPluginContext + ctx = TraceContextTextMapPropagator().extract(carrier={'traceparent': args.traceparent}) if args.traceparent else None + _stopped = threading.Event() terminate_on_parent_death_thread = threading.Thread( target=terminate_on_parent_death, args=[_stopped, 1.0] ) with ErtPluginContext(logger=logging.getLogger(), trace_provider=tracer_provider) as context: terminate_on_parent_death_thread.start() - with tracer.start_as_current_span(f"run_storage_server") as currentSpan: + with tracer.start_as_current_span(f"run_storage_server", ctx) as currentSpan: + logger = logging.getLogger("ert.shared.storage.info") try: - print(f"Opertation ID: {get_trace_id()}") + logger.info("Starting dark storage") run_server(args, debug=False, uvicorn_config = uvicorn_config) - except BaseException as err: - print(f"Stopped with exception {err}") + except SystemExit: + logger.info("Stopping dark storage") finally: _stopped.set() terminate_on_parent_death_thread.join() - print("Closing2") def sigterm_handler(_signo, _stack_frame): - print("handle sigterm") sys.exit(0) signal.signal(signal.SIGTERM, sigterm_handler) diff --git a/src/ert/services/storage_service.py b/src/ert/services/storage_service.py index 38914415fc8..694fae11d4d 100644 --- a/src/ert/services/storage_service.py +++ b/src/ert/services/storage_service.py @@ -9,6 +9,7 @@ from ert.dark_storage.client import Client, ConnInfo from ert.services._base_service import BaseService, _Context, local_exec_args +from ert.trace import get_traceparent from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor HTTPXClientInstrumentor().instrument() @@ -23,6 +24,7 @@ def __init__( conn_info: Mapping[str, Any] | Exception | None = None, project: str | None = None, verbose: bool = False, + traceparent: str | None = "inherit_parent" ): self._url: str | None = None @@ -31,6 +33,9 @@ def __init__( exec_args.extend(["--project", str(project)]) if verbose: exec_args.append("--verbose") + if traceparent: + traceparent = get_traceparent() if traceparent == "inherit_parent" else traceparent + exec_args.extend(["--traceparent", str(traceparent)]) super().__init__(exec_args, timeout, conn_info, project) diff --git a/src/ert/shared/storage/command.py b/src/ert/shared/storage/command.py index 05bb63e9fbb..73be6dcd75b 100644 --- a/src/ert/shared/storage/command.py +++ b/src/ert/shared/storage/command.py @@ -16,6 +16,12 @@ def add_parser_options(ap: ArgumentParser) -> None: help="Path to directory in which to create storage_server.json", default=os.getcwd(), ) + ap.add_argument( + "--traceparent", + type=str, + help="Trace parent id to be used by the storage root span", + default=None, + ) ap.add_argument( "--host", type=str, default=os.environ.get("ERT_STORAGE_HOST", "127.0.0.1") ) diff --git a/src/ert/trace.py b/src/ert/trace.py index c7a24b48b1c..2d98eba4483 100644 --- a/src/ert/trace.py +++ b/src/ert/trace.py @@ -1,6 +1,7 @@ from opentelemetry import trace from opentelemetry.sdk.resources import SERVICE_NAME, Resource from opentelemetry.sdk.trace import SpanLimits, TracerProvider +from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator resource = Resource(attributes={SERVICE_NAME: "ert"}) tracer_provider = TracerProvider( @@ -13,3 +14,9 @@ def get_trace_id() -> str: return trace.format_trace_id(trace.get_current_span().get_span_context().trace_id) + +def get_traceparent() -> str | None: + carrier = {} + # Write the current context into the carrier. + TraceContextTextMapPropagator().inject(carrier) + return carrier.get('traceparent') \ No newline at end of file