-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Custom metric support #384
Conversation
Could you add a link in the PR description to the GitHub / Jira issue that motivates the changes? |
I linked this PR from that issue: #369. I will update the description here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have the necessary familiarity with the metrics code and Python-Rust bridge to review this properly, but it looks very clean, well-tested and plausible to me. So just in case you feel happy merging without expert review, here's my approval.
# sync function and we don't support cross-process metrics | ||
if not self.runtime_metric_meter: | ||
raise RuntimeError( | ||
"Metrics meter not available in non-threaded sync activities like mulitprocess" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Metrics meter not available in non-threaded sync activities like mulitprocess" | |
"Metrics meter not available in non-threaded sync activities like multiprocess" |
if not ref: | ||
return None | ||
return MetricMeter(ref) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a personal Python style suggestion, obviously FFTI.
if not ref: | |
return None | |
return MetricMeter(ref) | |
return MetricMeter(ref) if ref else None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I try to avoid the RHS ternary in some of these cases, but you'll see I use it in others. I may use it here.
for k, v in at_least_labels.items(): | ||
if not f'{k}="{v}"' in line: | ||
return False | ||
return line.endswith(f" {value}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More small-minded personal style suggestions while trying to digest the PR, FFTI!
for k, v in at_least_labels.items(): | |
if not f'{k}="{v}"' in line: | |
return False | |
return line.endswith(f" {value}") | |
return all( | |
f'{k}="{v}"' in line for k, v in at_least_labels.items() | |
) and line.endswith(f" {value}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's style preference. I do use any
/all
where I do think functional approach has more value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, here I would personally say that all(...)
is more Pythonic than explicitly implementing an early-exit algorithm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 (just test code, and this style for assert is clearer with pytest because of how it expands the expression, but no assert in here so can change)
"""Initialize gauge.""" | ||
self._ref = meter._ref.new_gauge(name, description, unit) | ||
|
||
def set(self, value: int, attrs: MetricAttributes) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't value supposed to be a float here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like otel metrics support both floats and ints for all metric types.
I think we should too.
https://github.com/open-telemetry/opentelemetry-python/blob/main/opentelemetry-api/src/opentelemetry/metrics/_internal/instrument.py#L319
https://github.com/open-telemetry/opentelemetry-go/tree/main/metric
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opened an issue in sdk-core temporalio/sdk-core#604
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that should be a blocker for this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, I would want float support though but that can be added later when it’s supported in core
What was changed
MetricMeter
,MetricCounter
,MetricHistogram
, andMetricGauge
as (abstract) classes totemporalio.common
metric_meter
property totemporalio.runtime.Runtime
temporalio.workflow.metric_meter()
function to get replay-safe metric metertemporalio.activity.metric_meter()
function to get optional metric metermetric_meter
attribute totemporalio.testing.ActivityEnvironment
that defaults to noop implHandles part of #369