Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
96852c2
Implementing first version of metrics for gRPC server
lorenzoronzani May 22, 2026
f1c46a0
created a constant
lorenzoronzani May 22, 2026
543acb5
Implemented metrics into client
lorenzoronzani May 22, 2026
e8a48c9
Added aio clients and servers
lorenzoronzani May 22, 2026
53e4b08
Edited client
lorenzoronzani May 22, 2026
55dd9c0
Removed None
lorenzoronzani May 22, 2026
cf6e4b3
Added changelog edit
lorenzoronzani May 22, 2026
d25bf7d
Merge branch 'main' into feature/add-metrics-to-grpc
emdneto May 22, 2026
3ea4785
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani May 26, 2026
519fec7
Integrated first 3 comments
lorenzoronzani May 27, 2026
2702b3f
ruff
lorenzoronzani May 27, 2026
48a90e2
Integrated comments
lorenzoronzani May 27, 2026
5219282
Integrated comments
lorenzoronzani May 27, 2026
216df09
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jun 2, 2026
5b45ee1
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jun 3, 2026
2146c14
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jun 8, 2026
f30c668
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jun 15, 2026
b2357b9
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jun 18, 2026
46cdbcd
Addressed lint/style cmments
lorenzoronzani Jun 18, 2026
452a088
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jun 22, 2026
91d824d
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jun 25, 2026
28b8de0
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jun 30, 2026
fe4263c
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jul 1, 2026
7b513a1
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jul 7, 2026
b3696df
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jul 9, 2026
f9c7d28
Merge branch 'main' into feature/add-metrics-to-grpc
lorenzoronzani Jul 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changelog/4621.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`opentelemetry-instrumentation-grpc`: add rpc.client.call.duration and rpc.server.call.duration metrics for both sync and async components
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ async def serve():
from opentelemetry.instrumentation.grpc.version import __version__
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.utils import unwrap
from opentelemetry.metrics import get_meter

# pylint:disable=import-outside-toplevel
# pylint:disable=import-self
Expand Down Expand Up @@ -326,6 +327,7 @@ def instrumentation_dependencies(self) -> Collection[str]:
def _instrument(self, **kwargs):
self._original_func = grpc.server
tracer_provider = kwargs.get("tracer_provider")
meter_provider = kwargs.get("meter_provider")

def server(*args, **kwargs):
if "interceptors" in kwargs and kwargs["interceptors"]:
Expand All @@ -334,13 +336,17 @@ def server(*args, **kwargs):
kwargs["interceptors"].insert(
0,
server_interceptor(
tracer_provider=tracer_provider, filter_=self._filter
tracer_provider=tracer_provider,
filter_=self._filter,
meter_provider=meter_provider,
),
)
else:
kwargs["interceptors"] = [
server_interceptor(
tracer_provider=tracer_provider, filter_=self._filter
tracer_provider=tracer_provider,
filter_=self._filter,
meter_provider=meter_provider,
)
]

Expand Down Expand Up @@ -380,6 +386,7 @@ def instrumentation_dependencies(self) -> Collection[str]:
def _instrument(self, **kwargs):
self._original_func = grpc.aio.server
tracer_provider = kwargs.get("tracer_provider")
meter_provider = kwargs.get("meter_provider")

def server(*args, **kwargs):
if "interceptors" in kwargs and kwargs["interceptors"]:
Expand All @@ -388,13 +395,17 @@ def server(*args, **kwargs):
kwargs["interceptors"].insert(
0,
aio_server_interceptor(
tracer_provider=tracer_provider, filter_=self._filter
tracer_provider=tracer_provider,
filter_=self._filter,
meter_provider=meter_provider,
),
)
else:
kwargs["interceptors"] = [
aio_server_interceptor(
tracer_provider=tracer_provider, filter_=self._filter
tracer_provider=tracer_provider,
filter_=self._filter,
meter_provider=meter_provider,
)
]
return self._original_func(*args, **kwargs)
Expand Down Expand Up @@ -457,6 +468,8 @@ def instrumentation_dependencies(self) -> Collection[str]:
def _instrument(self, **kwargs):
self._request_hook = kwargs.get("request_hook")
self._response_hook = kwargs.get("response_hook")
self._tracer_provider = kwargs.get("tracer_provider")
self._meter_provider = kwargs.get("meter_provider")
for ctype in self._which_channel(kwargs):
_wrap(
"grpc",
Expand All @@ -470,16 +483,16 @@ def _uninstrument(self, **kwargs):

def wrapper_fn(self, original_func, instance, args, kwargs):
channel = original_func(*args, **kwargs)
tracer_provider = kwargs.get("tracer_provider")
request_hook = self._request_hook
response_hook = self._response_hook
target = args[0] if args else kwargs.get("target")
return intercept_channel(
channel,
client_interceptor(
tracer_provider=tracer_provider,
tracer_provider=self._tracer_provider,
filter_=self._filter,
request_hook=request_hook,
response_hook=response_hook,
request_hook=self._request_hook,
response_hook=self._response_hook,
meter_provider=self._meter_provider,
target=target,
),
Comment thread
lorenzoronzani marked this conversation as resolved.
)

Expand Down Expand Up @@ -511,25 +524,21 @@ def __init__(self, filter_=None):
def instrumentation_dependencies(self) -> Collection[str]:
return _instruments

def _add_interceptors(self, tracer_provider, kwargs):
def _add_interceptors(self, tracer_provider, meter_provider, target, kwargs):
interceptors = aio_client_interceptors(
tracer_provider=tracer_provider,
filter_=self._filter,
request_hook=self._request_hook,
response_hook=self._response_hook,
meter_provider=meter_provider,
target=target,
)
if "interceptors" in kwargs and kwargs["interceptors"]:
kwargs["interceptors"] = list(kwargs["interceptors"])
kwargs["interceptors"] = (
aio_client_interceptors(
tracer_provider=tracer_provider,
filter_=self._filter,
request_hook=self._request_hook,
response_hook=self._response_hook,
)
+ kwargs["interceptors"]
kwargs["interceptors"] = interceptors + list(
kwargs["interceptors"]
)
else:
kwargs["interceptors"] = aio_client_interceptors(
tracer_provider=tracer_provider,
filter_=self._filter,
request_hook=self._request_hook,
response_hook=self._response_hook,
)
kwargs["interceptors"] = interceptors

return kwargs

Expand All @@ -539,15 +548,20 @@ def _instrument(self, **kwargs):
self._request_hook = kwargs.get("request_hook")
self._response_hook = kwargs.get("response_hook")
tracer_provider = kwargs.get("tracer_provider")
meter_provider = kwargs.get("meter_provider")

def insecure(*args, **kwargs):
kwargs = self._add_interceptors(tracer_provider, kwargs)

target = args[0] if args else kwargs.get("target")
kwargs = self._add_interceptors(
tracer_provider, meter_provider, target, kwargs
)
return self._original_insecure(*args, **kwargs)

def secure(*args, **kwargs):
kwargs = self._add_interceptors(tracer_provider, kwargs)

target = args[0] if args else kwargs.get("target")
kwargs = self._add_interceptors(
tracer_provider, meter_provider, target, kwargs
)
return self._original_secure(*args, **kwargs)

Comment thread
lorenzoronzani marked this conversation as resolved.
grpc.aio.insecure_channel = insecure
Expand All @@ -559,7 +573,12 @@ def _uninstrument(self, **kwargs):


def client_interceptor(
tracer_provider=None, filter_=None, request_hook=None, response_hook=None
tracer_provider=None,
filter_=None,
request_hook=None,
response_hook=None,
meter_provider=None,
target=None,
):
"""Create a gRPC client channel interceptor.

Expand All @@ -570,6 +589,10 @@ def client_interceptor(
matches the condition. Default is None and intercept
all requests.

meter_provider: The meter provider to use for metrics.

target: The target address of the channel (e.g. "host:port").

Returns:
An invocation-side interceptor object.
"""
Expand All @@ -582,15 +605,23 @@ def client_interceptor(
schema_url="https://opentelemetry.io/schemas/1.11.0",
)

meter = get_meter(
__name__,
__version__,
meter_provider,
)

return _client.OpenTelemetryClientInterceptor(
tracer,
filter_=filter_,
request_hook=request_hook,
response_hook=response_hook,
meter=meter,
target=target,
)


def server_interceptor(tracer_provider=None, filter_=None):
def server_interceptor(tracer_provider=None, filter_=None, meter_provider=None):
"""Create a gRPC server interceptor.

Args:
Expand All @@ -600,6 +631,8 @@ def server_interceptor(tracer_provider=None, filter_=None):
matches the condition. Default is None and intercept
all requests.

meter_provider: The meter provider to use for metrics.

Returns:
A service-side interceptor object.
"""
Expand All @@ -612,17 +645,34 @@ def server_interceptor(tracer_provider=None, filter_=None):
schema_url="https://opentelemetry.io/schemas/1.11.0",
)

return _server.OpenTelemetryServerInterceptor(tracer, filter_=filter_)
meter = get_meter(
__name__,
__version__,
meter_provider,
)
Comment thread
lorenzoronzani marked this conversation as resolved.

return _server.OpenTelemetryServerInterceptor(
tracer, filter_=filter_, meter=meter
)


def aio_client_interceptors(
tracer_provider=None, filter_=None, request_hook=None, response_hook=None
tracer_provider=None,
filter_=None,
request_hook=None,
response_hook=None,
meter_provider=None,
target=None,
):
"""Create a gRPC client channel interceptor.

Args:
tracer: The tracer to use to create client-side spans.

meter_provider: The meter provider to use for metrics.

target: The target address of the channel (e.g. "host:port").

Returns:
An invocation-side interceptor object.
"""
Expand All @@ -635,40 +685,38 @@ def aio_client_interceptors(
schema_url="https://opentelemetry.io/schemas/1.11.0",
)

meter = get_meter(
__name__,
__version__,
meter_provider,
)

common_kwargs = {
"filter_": filter_,
"request_hook": request_hook,
"response_hook": response_hook,
"meter": meter,
"target": target,
}

return [
_aio_client.UnaryUnaryAioClientInterceptor(
tracer,
filter_=filter_,
request_hook=request_hook,
response_hook=response_hook,
),
_aio_client.UnaryStreamAioClientInterceptor(
tracer,
filter_=filter_,
request_hook=request_hook,
response_hook=response_hook,
),
_aio_client.StreamUnaryAioClientInterceptor(
tracer,
filter_=filter_,
request_hook=request_hook,
response_hook=response_hook,
),
_aio_client.UnaryUnaryAioClientInterceptor(tracer, **common_kwargs),
_aio_client.UnaryStreamAioClientInterceptor(tracer, **common_kwargs),
_aio_client.StreamUnaryAioClientInterceptor(tracer, **common_kwargs),
_aio_client.StreamStreamAioClientInterceptor(
tracer,
filter_=filter_,
request_hook=request_hook,
response_hook=response_hook,
tracer, **common_kwargs
),
]


def aio_server_interceptor(tracer_provider=None, filter_=None):
def aio_server_interceptor(tracer_provider=None, filter_=None, meter_provider=None):
"""Create a gRPC aio server interceptor.

Args:
tracer: The tracer to use to create server-side spans.

meter_provider: The meter provider to use for metrics.

Returns:
A service-side interceptor object.
"""
Expand All @@ -681,8 +729,14 @@ def aio_server_interceptor(tracer_provider=None, filter_=None):
schema_url="https://opentelemetry.io/schemas/1.11.0",
)

meter = get_meter(
__name__,
__version__,
meter_provider,
)

return _aio_server.OpenTelemetryAioServerInterceptor(
tracer, filter_=filter_
tracer, filter_=filter_, meter=meter
)


Expand Down
Loading