简体   繁体   English

在 Micrometer 中为动态指标设置描述的简洁方法是什么?

[英]What is a clean way of setting description for dynamic metrics in Micrometer?

This may sound silly and may have a really simple answer however I haven't found any yet.这可能听起来很傻,可能有一个非常简单的答案,但我还没有找到任何答案。

Micrometer has Builder classes for each of the metric type of the following form: Micrometer 具有以下形式的每种度量类型的 Builder 类:

<MetricType>.builder(<metricName>).description(<description>).tags(<tagsArray>).register(<meterRegistry>)

Lets take Counter metrics as an example.让我们以 Counter 指标为例。 It can be incremented as follows:它可以按如下方式递增:

<meterRegistry>.Counter(<counterName>, <Pairs of labels and their values>).increment()

The problem arises when you want to set the description.当您要设置描述时,就会出现问题。 If the values of labels are dynamic in nature ie the values are decided at run time or if the possible combination of labels is too many like 10+ then how are you supposed to set the description?如果标签的值本质上是动态的,即值是在运行时决定的,或者标签的可能组合太多(如 10+),那么您应该如何设置描述?

The only solution I could think of is to store the description somewhere when starting the metric service.我能想到的唯一解决方案是在启动度量服务时将描述存储在某处。 Then create a wrapper around the increment method.然后围绕增量方法创建一个包装器。 Now, when the user calls the wrapper, call the register method (with the stored description) and then the increment method.现在,当用户调用包装器时,调用 register 方法(带有存储的描述),然后调用 increment 方法。 And afaik the register method creates a new metric if it doesn't exist otherwise returns the existing metric.如果注册方法不存在,则注册方法会创建一个新指标,否则将返回现有指标。

The same problem could be easily resolved in Prometheus as they have a register method that lets you set all the labels (ie keys only) and the description.在 Prometheus 中可以轻松解决相同的问题,因为它们有一个注册方法,可以让您设置所有标签(即仅键)和描述。 The increment method then only requires the values of those labels.然后,增量方法只需要这些标签的值。

Does micrometer provide similar functionality?千分尺是否提供类似的功能? Creating a wrapper for a simple application seems highly inconvenient.为简单的应用程序创建包装器似乎非常不方便。 And considering that micrometer is already a wrapper around Prometheus (and other instrumenting services), I don't want to create a wrapper around it as well.考虑到千分尺已经是 Prometheus(和其他仪器服务)的包装器,我也不想围绕它创建一个包装器。

If the question doesn't make sense the following example may help:如果问题没有意义,以下示例可能会有所帮助:

Let's consider a Counter metric requests with label type whose value can be alpha, beta, gamma with the description being tracks requests from clients让我们考虑一个带有 label type的 Counter metric requests ,其值可以是alpha, beta, gamma ,其描述是tracks requests from clients

Then as a solution I can add the following line in register function called when starting the metric service.然后作为解决方案,我可以在启动度量服务时调用的寄存器 function 中添加以下行。

Counter.builder("requests")
    .description("tracks requests from clients)
    .tags("type", "alpha")
    .register(meterRegistry);

And then wherever I want to use this metric I can run the following code:然后无论我想在哪里使用这个指标,我都可以运行以下代码:

meterRegistry.Counter("request", "type", <valueOfType>).increment()

My concern is that in this solution I am initiating only the alpha type which doesn't seem right since that is the only type.我担心的是,在这个解决方案中,我只启动了看起来不正确的alpha类型,因为这是唯一的类型。 Another option would be to register all 3 types, however, this is assuming all the possible values are known during runtime.另一种选择是注册所有 3 种类型,但是,这是假设所有可能的值在运行时都是已知的。 If the values are discovered at runtime, this solution fails completely and now you have to use the solution with wrappers as described above or forget description altogether.如果在运行时发现了这些值,则此解决方案将完全失败,现在您必须使用带有上述包装器的解决方案,或者完全忘记描述。

I came across a similar problem, when trying to work with Counters and multiple value for a single Tag.在尝试使用计数器和单个标签的多个值时,我遇到了类似的问题。

Here is my solution:这是我的解决方案:

@RestController
public class HelloController {

    private final Counter.Builder counter;
    private MeterRegistry registry;

    public HelloController(MeterRegistry registry) {
        this.counter = Counter.builder("counter").description("A description");
        this.registry = registry;
    }

    @GetMapping("/count")
    public String count1() {
        counter.tag("tag2", "value1").register(registry).increment();
// I don't provide more description here, but I need to use .register('registry') at each call.
        return "Count";
    }

    @GetMapping("/count2")
    public String count2() {
        counter.tag("tag2", "value2").register(registry).increment();
        return "Count";
    }

}
  • Note: I have to call counter...register(registry) in order to have a single description, and multiple value for tags.注意:我必须调用counter...register(registry)才能获得单一描述和标签的多个值。

I was struggle with your same problem, so I found this helpful post , but... I didn't liked this solution.我正在为同样的问题而苦苦挣扎,所以我发现了这篇有用的帖子,但是......我不喜欢这个解决方案。

I think te better approach is a placeholder one, like this .我认为更好的方法是占位符,就像这样 So maybe define a HierarchicalNameMapper that will replace tag placeholder when tag keys match it, it's good choice.所以也许定义一个HierarchicalNameMapper ,当标签键匹配它时替换标签占位符,这是一个不错的选择。

So now the problem of dynamic tagging meters seems to be solved, but the description still remains a problem.所以现在动态标注米的问题似乎解决了,但是描述仍然是个问题。 So I didn't use this solution too.所以我也没有使用这个解决方案。

My final solution was to store Counters Gauges and other Meters in maps and retrieving by Ids (Name and tags).我的最终解决方案是将Counters Gauges和其他仪表存储在地图中,并按 ID(名称和标签)检索。 The description was provided during measurements, where I lookup the map and if a metric with that Id already exists will be incremented (or decremented) otherwise will be created with a description based on a meaningful metric name and tag keys-values.描述是在测量期间提供的,我在其中查找 map,如果具有该 Id 的指标已经存在,则将增加(或减少),否则将使用基于有意义的指标名称和标签键值的描述创建。

    /**
     * Increment the {@link Counter}  with input tags. If it does not exists it will be created.
     */
    public void increment(String description, String unit, Tags tags) throws MetricsException {
            this.counter(description, unit, tags).increment();
    }

    /**
     * Search for a counter with input tags. If it does not exists it will be created.
     */
    private Counter counter(String description, String unit, Tags tags) {
        final String counterId = name.concat(tags.toString());

        Counter counter = counters.get(counterId);
        if (counter == null) {

            counter = Counter.builder(name)
                    .description(description)
                    .baseUnit(unit)
                    .tags(tags)
                    .register(registry);

            counters.put(counterId, counter);
        }

        return counter;
    }

Where:在哪里:
registry is MeterRegistry field value registryMeterRegistry字段值
counters is a Map<String, Counter> counters是一个Map<String, Counter>

If you are struggling about memory usage, I used a Java instrumentation agent to inspect the Map.如果您对 memory 的使用感到困扰,我使用 Java 仪器代理来检查 Map。 This one .这个 An entry of the map is like 1KB, so you should have like 1000 tag-names combination to use 1MB:) map 的条目就像 1KB,所以你应该有 1000 个标签名组合才能使用 1MB :)

This was the solution that fitted best for me.这是最适合我的解决方案。 Let me know if this helped you:)让我知道这是否对您有帮助:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM