Skip to content
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

Add scope info and version to Prometheus exporter #5086

Merged

Conversation

robertcoltheart
Copy link
Contributor

@robertcoltheart robertcoltheart commented Nov 27, 2023

Fixes #3972

Changes

Add instrument scope info and version to Prometheus exporter as per https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/compatibility/prometheus_and_openmetrics.md#instrumentation-scope-1

Scope info is automatically added to the Prometheus exporters.

Before this change:

# TYPE MyFruitCounter_total counter
MyFruitCounter_total{color="red",name="apple"} 66 1702578315791
MyFruitCounter_total{color="yellow",name="lemon"} 77 1702578315791
MyFruitCounter_total{color="green",name="apple"} 22 1702578315791

# EOF

After (with no Accept header):

# TYPE otel_scope_info info
# HELP otel_scope_info Scope metadata
otel_scope_info{otel_scope_name="MyCompany.MyProduct.MyLibrary"} 1
# TYPE MyFruitCounter_total counter
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="red",name="apple"} 102 1702577575197
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="yellow",name="lemon"} 119 1702577575197
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="green",name="apple"} 34 1702577575197
# EOF

After (when passing Accept: application/openmetrics-text:

# TYPE otel_scope_info info
# HELP otel_scope_info Scope metadata
otel_scope_info{otel_scope_name="MyCompany.MyProduct.MyLibrary"} 1
# TYPE MyFruitCounter_total counter
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="red",name="apple"} 4692 1702577811.302
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="yellow",name="lemon"} 5474 1702577811.302
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="green",name="apple"} 1564 1702577811.302
# EOF

Merge requirement checklist

  • CONTRIBUTING guidelines followed (nullable enabled, static analysis, etc.)
  • Unit tests added/updated
  • Appropriate CHANGELOG.md files updated for non-trivial changes
  • Changes in public API reviewed (if applicable)

Copy link

linux-foundation-easycla bot commented Nov 27, 2023

CLA Signed

The committers listed above are authorized under a signed CLA.

@robertcoltheart robertcoltheart marked this pull request as ready for review November 27, 2023 22:16
@robertcoltheart robertcoltheart requested a review from a team as a code owner November 27, 2023 22:16
@utpilla
Copy link
Contributor

utpilla commented Nov 29, 2023

@robertcoltheart Thanks for sending out this PR! Could you fix the build errors?

@robertcoltheart
Copy link
Contributor Author

Fixed build errors, I think, can you re-run?

Copy link

codecov bot commented Nov 29, 2023

Codecov Report

Merging #5086 (a7cc5fd) into main (c0969d0) will increase coverage by 0.18%.
Report is 2 commits behind head on main.
The diff coverage is 88.09%.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #5086      +/-   ##
==========================================
+ Coverage   83.26%   83.45%   +0.18%     
==========================================
  Files         297      297              
  Lines       12366    12386      +20     
==========================================
+ Hits        10297    10337      +40     
+ Misses       2069     2049      -20     
Flag Coverage Δ
unittests 83.45% <88.09%> (+0.18%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Coverage Δ
...s.HttpListener/Internal/PrometheusSerializerExt.cs 100.00% <100.00%> (ø)
...heus.HttpListener/Internal/PrometheusSerializer.cs 84.86% <96.29%> (+3.26%) ⬆️
...tpListener/Internal/PrometheusCollectionManager.cs 77.58% <63.63%> (-1.47%) ⬇️

... and 6 files with indirect coverage changes

@utpilla
Copy link
Contributor

utpilla commented Nov 29, 2023

@robertcoltheart Could you run this example with a PrometheusExporter and share the scraped output? We would like to get an idea of how the serialized data looks like with these changes.

@robertcoltheart
Copy link
Contributor Author

@robertcoltheart Could you run this example with a PrometheusExporter and share the scraped output? We would like to get an idea of how the serialized data looks like with these changes.

Updated in the PR description from the example ASPNET app. The output is shortened a bit for brevity but shows histograms and counters with and without meter versions, and their respective otel_scope_info.

@cijothomas
Copy link
Member

@robertcoltheart Could you run this example with a PrometheusExporter and share the scraped output? We would like to get an idea of how the serialized data looks like with these changes.

Updated in the PR description from the example ASPNET app. The output is shortened a bit for brevity but shows histograms and counters with and without meter versions, and their respective otel_scope_info.

can you use this example? https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/docs/metrics/getting-started-prometheus-grafana/Program.cs and share the output with and without the feature?
I am not very sure where is meter.name,version supposed to show up.. Is that needed as part of every line? Or just once under "otel_scope_info"? Couple of examples would help with understanding the expected behavior. Thank you!

@robertcoltheart
Copy link
Contributor Author

Here is the before and after using the sample above:

Before:

# TYPE MyFruitCounter_total counter
MyFruitCounter_total{color="red",name="apple"} 66 1701348839180
MyFruitCounter_total{color="yellow",name="lemon"} 77 1701348839180
MyFruitCounter_total{color="green",name="apple"} 22 1701348839180
# EOF

After:

# TYPE otel_scope_info info
# HELP otel_scope_info Scope metadata
otel_scope_info{otel_scope_name="MyCompany.MyProduct.MyLibrary"} 1
# TYPE MyFruitCounter_total counter
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="red",name="apple"} 486 1701348794.500
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="yellow",name="lemon"} 567 1701348794.500
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="green",name="apple"} 162 1701348794.500
# EOF

@robertcoltheart
Copy link
Contributor Author

I took a lot of the changes in this PR from the Java version of OTEL. An example output of the Java metrics using the above format is below:

# TYPE target info
# HELP target Target metadata
target_info{service_name="PromExample",service_namespace="io.my.namespace",service_version="1.2.3",telemetry_sdk_language="java",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="1.26.0"} 1
# TYPE otel_scope_info info
# HELP otel_scope_info Scope metadata
otel_scope_info{otel_scope_name="io.example"} 1
# TYPE example_counter counter
# HELP example_counter 
example_counter_total{otel_scope_name="io.example"} 27.0 1701349347.895
# TYPE super_timer histogram
# HELP super_timer 
super_timer_count{otel_scope_name="io.example"} 27.0 1701349347.895
super_timer_sum{otel_scope_name="io.example"} 27293.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="0.0"} 0.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="5.0"} 0.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="10.0"} 0.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="25.0"} 0.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="50.0"} 0.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="75.0"} 0.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="100.0"} 0.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="250.0"} 0.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="500.0"} 0.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="750.0"} 0.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="1000.0"} 1.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="2500.0"} 27.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="5000.0"} 27.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="7500.0"} 27.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="10000.0"} 27.0 1701349347.895
super_timer_bucket{otel_scope_name="io.example",le="+Inf"} 27.0 1701349347.895
# EOF

@robertcoltheart robertcoltheart marked this pull request as ready for review December 7, 2023 12:07
@cijothomas
Copy link
Member

Here is the before and after using the sample above:

Before:

# TYPE MyFruitCounter_total counter
MyFruitCounter_total{color="red",name="apple"} 66 1701348839180
MyFruitCounter_total{color="yellow",name="lemon"} 77 1701348839180
MyFruitCounter_total{color="green",name="apple"} 22 1701348839180
# EOF

After:

# TYPE otel_scope_info info
# HELP otel_scope_info Scope metadata
otel_scope_info{otel_scope_name="MyCompany.MyProduct.MyLibrary"} 1
# TYPE MyFruitCounter_total counter
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="red",name="apple"} 486 1701348794.500
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="yellow",name="lemon"} 567 1701348794.500
MyFruitCounter_total{otel_scope_name="MyCompany.MyProduct.MyLibrary",otel_scope_version="1.0",color="green",name="apple"} 162 1701348794.500
# EOF

Could you make this example in the PR description to keep it easy to follow?

@utpilla utpilla merged commit 3c986e8 into open-telemetry:main Dec 15, 2023
78 checks passed
@robertcoltheart robertcoltheart deleted the feature/prometheus-scope-info branch December 15, 2023 00:58
@@ -3,6 +3,7 @@
## Unreleased

* Export OpenMetrics format from Prometheus exporters ([#5107](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5107))
* For requests with OpenMetrics format, scope info is automatically added ([#5086](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5086))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robertcoltheart Scope info is added regardless of whether OpenMetrics is added, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

otel_scope_name and otel_scope_version tags are added regardless of what is requested, yes. This mirrors the behavior of the Java OTEL library. The otel_scope_info is only added when OpenMetrics is requested, otherwise Prometheus doesn't know how to handle info types and will fault.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The otel_scope_info is only added when OpenMetrics is requested

The example that you provided in the PR description has otel_scope_info added for both the cases though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Damn, I don't know how I missed that. Sorry about that, let me raise a PR for that right now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See: #5182

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Prometheus exporter handles instrumentation scope and prevents collisions
4 participants