Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- When the `function.calls.duration` histogram is exported to Prometheus, it now
includes the units (`function_calls_duration_seconds`) to be in line with
Prometheus/OpenMetrics naming conventions. **Dashboards and alerting rules must be updated.**
- Struct methods now have the struct name as part of the `function` label on the metrics
(for example, `MyStruct::my_method`)

### Deprecated

Expand All @@ -38,7 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Return types on functions annotated with `#[autometrics]` containing generic
- Return types on functions annotated with `#[autometrics]` containing generic
`impl` types in their type arguments (`fn() -> Result<impl ToString, impl std::error::Error>`)
no longer fail to compile.

Expand Down
21 changes: 16 additions & 5 deletions autometrics-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::parse::{AutometricsArgs, Item};
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use proc_macro2::TokenStream;
use quote::quote;
use quote::{quote, ToTokens};
use std::env;
use syn::{
parse_macro_input, GenericArgument, ImplItem, ItemFn, ItemImpl, PathArguments, Result,
Expand All @@ -25,7 +25,7 @@ pub fn autometrics(
let item = parse_macro_input!(item as Item);

let result = match item {
Item::Function(item) => instrument_function(&args, item),
Item::Function(item) => instrument_function(&args, item, &None),
Item::Impl(item) => instrument_impl_block(&args, item),
};

Expand All @@ -46,12 +46,21 @@ pub fn result_labels(input: proc_macro::TokenStream) -> proc_macro::TokenStream
}

/// Add autometrics instrumentation to a single function
fn instrument_function(args: &AutometricsArgs, item: ItemFn) -> Result<TokenStream> {
fn instrument_function(
args: &AutometricsArgs,
item: ItemFn,
struct_name: &Option<String>,
) -> Result<TokenStream> {
let sig = item.sig;
let block = item.block;
let vis = item.vis;
let attrs = item.attrs;
let function_name = sig.ident.to_string();

// Methods are identified as Struct::method
let function_name = match struct_name {
Some(struct_name) => format!("{}::{}", struct_name, sig.ident.to_string()),
None => sig.ident.to_string(),
};

// The PROMETHEUS_URL can be configured by passing the environment variable during build time
let prometheus_url =
Expand Down Expand Up @@ -295,6 +304,8 @@ fn instrument_function(args: &AutometricsArgs, item: ItemFn) -> Result<TokenStre

/// Add autometrics instrumentation to an entire impl block
fn instrument_impl_block(args: &AutometricsArgs, mut item: ItemImpl) -> Result<TokenStream> {
let struct_name = Some(item.self_ty.to_token_stream().to_string());

// Replace all of the method items in place
item.items = item
.items
Expand All @@ -319,7 +330,7 @@ fn instrument_impl_block(args: &AutometricsArgs, mut item: ItemImpl) -> Result<T
sig: method.sig,
block: Box::new(method.block),
};
let tokens = match instrument_function(args, item_fn) {
let tokens = match instrument_function(args, item_fn, &struct_name) {
Ok(tokens) => tokens,
Err(err) => err.to_compile_error(),
};
Expand Down
8 changes: 4 additions & 4 deletions autometrics/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,22 @@ fn impl_block() {
let metrics = prometheus_exporter::encode_to_string().unwrap();
assert!(metrics.lines().any(|line| {
line.starts_with("function_calls_total{")
&& line.contains(r#"function="test_fn""#)
&& line.contains(r#"function="Foo::test_fn""#)
&& line.ends_with("} 1")
}));
assert!(metrics.lines().any(|line| line
.starts_with("function_calls_duration_seconds_bucket{")
&& line.contains(r#"function="test_fn""#)
&& line.contains(r#"function="Foo::test_fn""#)
&& line.ends_with("} 1")));

assert!(metrics.lines().any(|line| {
line.starts_with("function_calls_total{")
&& line.contains(r#"function="test_method""#)
&& line.contains(r#"function="Foo::test_method""#)
&& line.ends_with("} 1")
}));
assert!(metrics.lines().any(|line| line
.starts_with("function_calls_duration_seconds_bucket{")
&& line.contains(r#"function="test_method""#)
&& line.contains(r#"function="Foo::test_method""#)
&& line.ends_with("} 1")));
}

Expand Down