This is a request for an enhancement to the Spring Boot 2.0 actuator metrics endpoint.

It is common within prometheus to capture application metadata (e.g. version) as labels on a single metric (see https://www.robustperception.io/exposing-the-software-version-to-prometheus/).

I would propose creating (and exposing by default) an ApplicationInfoMetrics implementation of MeterBinder which converts all of the registered InfoContributor data to tags on a Guage named 'application.info' with a value of 1.0. The info JSON would be flattened for the tag names:

{
    "git": {
        "commit": {
            "id": "4616b7b"
        },
        "branch": "master"
    },
    "build": {
        "version": "0.0.1-SNAPSHOT",
        "artifact": "myapp",
        "name": "My Application",
        "group": "mygroup"
    }
}

would convert to the following prometheus metric:

# HELP application_info Application info
# TYPE application_info gauge
application_info{build_artifact="myapp",build_group="mygroup",build_name="My Application",build_version="0.0.1-SNAPSHOT",git_branch="master",git_commit_id="4616b7b"} 1.0

It would also be nice to have a configuration option for excluding/including InfoContributor fields for conversion to tags.

Comment From: wilkinsona

What do you think, @jkschneider?

Comment From: jkschneider

Interesting. WDYT @checketts?

I don't imagine any of this would be autoconfigurable, do you? We provide the binder, you provide the inputs?

Comment From: checketts

I like it. It would be autoconfigurable in the same way the ApplicationInfoMetrics works. I believe the user has to provide the property values themselves.

@jondavidnd1 I think initially excluding fields for use as tags won't be a problem in regards to metric cardinality. But probably should be included just incase users run into a value they don't want exposed or is problematic and needs to be stripped. It isn't too urgent in regards to prometheus since it allow you to drop labels on ingestion via configuration.

Comment From: jondavidnd1

Glad to hear you think the idea has merit.

I would think this would be completely autoconfigurable even if not enabled by default. Spring boot provides several InfoContributors (Git, Build, Environment) out of the box, and users can register more as beans. Those InfoContributors can be read at startup time to configure the application_info metric. That is how I have it implemented in my project.

@checketts Did you mean a different class when you said ApplicationInfoMetrics? I searched the spring-boot and micrometer repos and didn't see anything by that name.

Comment From: jkschneider

@jondavidnd1 Would you mind submitting a PR with the implementation you have in your project?

Comment From: snicoll

I am not fully sure I understand the issue but some apps may have info that aren't relevant to this at all. For instance, would start.spring.io/actuator/info be relevant? (Genuinely asking as I am not sure I understood the feature yet).

If not, perhaps we should be focusing on including things (with a default) rather than grabbing everything by default.

Comment From: jondavidnd1

@snicoll To answer your question about start.spring.io/actuator/info, yes, the way I envisioned the feature, all information on the actuator info endpoint would be available as a tag on the application_info guage unless (assuming these configuration options are available) you configure the ApplicationInfoMetrics to only include explicitly specified tags, or to include all tags with some tags explicitly excluded.

Now, for your example, a lot of that dependency data may not be valuable for queries against metrics in prometheus. In our projects, we've found it extremely valuable to be able to see the git and build information in the query results (those are the only InfoContributor elements we have enabled).

If you want to completely divest this feature from the info endpoint that may make sense, but for my use case, since spring-boot already had all the information I wanted on the info endpoint, it made sense to use it.

Comment From: jondavidnd1

@jkschneider I wouldn't mind submitting a PR at all, but I may need to a few days to get approval as the code in question was developed for my employer.

Comment From: checketts

Did you mean a different class when you said ApplicationInfoMetrics

Sorry @jondavidnd1 i was just refering the class you had mentioned in your first post. I wasn't referring to a specific class.

Comment From: tbilou

I would like to pick this up and give it a shot if nobody objects, since there's been no movement here in the last 3 months. I've read though it and I think I understand what @jondavidnd1 is asking for, so I think it's feasible to provide a first PR soon.

Comment From: wilkinsona

@tbilou Thank you, but I think we should wait and see if @jondavidnd1 is able to submit their existing implementation. @jondavidnd1, how are you getting on with that?

Comment From: jondavidnd1

I apologize for the extreme delay and lack of communication. There has been quite a bit of confusion with regard to corporate policy and contributing back to the project. @wilkinsona, if @tbilou is will to take a crack at a PR, I would say go ahead.

Comment From: wilkinsona

Thank you, @jondavidnd1. Over to you, @tbilou.

Comment From: tbilou

I have a PR ready (https://github.com/spring-projects/spring-boot/pull/13946) Need someone to have a look particularly at the flattenkeys method. There has to be something like this available in the existing code base already that we probably can reuse here instead of creating yet another recursive function that traverses a map...

Comment From: philwebb

It might have already been discussed, but using a tag contributor to apply a global tag (of the SHA or version) to all metrics seems like a better way to slice and dice metrics.

Comment From: wilkinsona

Applying a global tag can be done with a MeterRegistryCustomizer bean. For example, here's one that applies the git commit ID has a tag to all meters:

@Bean
public MeterRegistryCustomizer<?> gitTag(GitProperties gitProperties) {
    return (meterRegistry) -> meterRegistry.config().commonTags("git.commit", gitProperties.getCommitId());
}

This is our recommended approach and it's something that can already be done with the current API.