On September 15, 2026, JetBrains published a technical explanation of how the Service Map feature in the OpenTelemetry plugin works. The feature maps the actual relationships between microservices while the application is running inside the development environment. The explanation was prepared by Nikita Dukin and Egor Klimov as part of a collaboration between the Rider Execution team and the Software Engineering Research team.
The idea starts with a familiar practical problem: an architecture diagram may look organized, but it might reflect the state of the system from months ago and fail to show a new service or a message queue whose documentation has not been updated. JetBrains believes that static code analysis is not always sufficient, because it describes what may happen in the source code, not what actually happens between services at runtime.
Traces Are the Map’s Source
The plugin relies on OpenTelemetry data, which collects logs, metrics, and traces. While logs explain what happened and metrics show the scale of a phenomenon, traces reveal the request’s path through the system. Each trace consists of units of work called spans, and OpenTelemetry provides standardized semantic conventions for them, such as HTTP Client and HTTP Server spans.
The plugin uses these traces to understand the operational architecture without tying the algorithm to a particular framework or language. If applications and libraries send traces according to OpenTelemetry expectations, the feature can visualize communications regardless of the technology used. JetBrains states that the same logic can work with JVM, .NET, Python, Go, and other applications, and can also be used in IntelliJ IDEA, GoLand, PyCharm, WebStorm, and Rider.
How Is the Map Built Inside the Development Environment?
When the development environment is running with the OpenTelemetry plugin enabled, the plugin starts a lightweight local server that receives telemetry data. When the application starts, the plugin sets the standard OpenTelemetry environment variables so that the application sends its traces to that local server.
The server processes incoming traces asynchronously, builds an internal model of the architecture, and continuously updates it. When the Service Map tab is opened, the plugin retrieves the latest structural model and displays it as a visual diagram. Thus, the map is not a static document created manually, but a direct result of the communications observed by the system while it is running.
The Challenge Is Not Drawing but Interpreting the Data
Traces arrive independently, and there is no guarantee regarding the order in which they arrive. A child-service trace may arrive before the parent-service trace, and tracing does not announce a final completion moment that guarantees no late trace will arrive. In addition, OpenTelemetry does not provide a strict, separate type for each trace; traces carry a map of key-value pairs that describes the operation’s meaning.
For this reason, JetBrains classified architectural reconstruction as a data-stream-processing algorithm. The plugin does not wait for a trace to be complete; instead, it examines each trace as soon as it arrives. It uses attributes such as http.request.method and http.response.status_code to determine whether the operation is an HTTP connection, while other attributes indicate a database query or interaction with a messaging system.
After classifying the trace, the algorithm determines which service produced it. If the service is new, it is added to the map; if it already exists, the new data is merged with it and its statistics are updated. For HTTP connections, the plugin looks for the relationship between the CLIENT span issued by the calling service and the SERVER span produced in the receiving service. Trace context travels with the request, making the SERVER span a child of the CLIENT span. If the other endpoint exists, the relationship is drawn immediately; if it does not, the span is kept in memory until the corresponding data arrives.
Other dependencies use different rules. A database call is usually represented by a single CLIENT span, from which the plugin infers the database node based on semantic attributes. Messaging systems require greater flexibility, because the producer-consumer relationship may appear through a parent-child relationship or through span links, depending on the messaging system and the instrumentation method used.
Why Does This Matter in Practice?
The core value here is that the map reveals observed behavior, not merely the expected architecture. If the system shows several HTTP connections or database queries during development when one connection was expected, this can be discovered before release. The map also helps explain dependencies that were not documented or that changed over time.
However, the accuracy of the result remains tied to the quality of the telemetry. The algorithm needs correct traces, propagation of trace context between services, and use of the expected semantic attributes. Therefore, Service Map does not automatically provide a complete picture of every system simply because the plugin is installed; anything that the instrumentation tools do not send, or that arrives without context, may not appear in the inferred relationships. The article also explains that the model evolves as new evidence arrives, making the map an updated operational representation rather than a final judgment on the architectural design.