【问题标题】:Using regex to retrieve the Prometheus metric name from Grafana expressions使用正则表达式从 Grafana 表达式中检索 Prometheus 指标名称
【发布时间】:2019-01-12 05:12:14
【问题描述】:

我尝试了许多不同的regex 模式来获得它,但不是很成功。

这个问题的模式:

<method_name(> metric_name <{filter_condition}> <[time_duration]> <)> <by (some members)>
            ^------------------------------------------------------^
                          method_name(...) can be multiple

如您所见,&lt;...&gt; 可以是可选的,而metric_name 是必须的,我想从这个equation 中检索它。

Case # 1
input: sum(log_search_by_service_total {service_name!~\"\"}) by (service_name, operator)
output: log_search_by_service_total

Case # 2
input: log_request_total
output: log_request_total

Case # 3
input:  sum(delta(log_request_total[5m])) by (args, user_id)
output: log_request_total

Case # 4
input: log_request_total{methodName=~\"getAppDynamicsGraphMetrics|getAppDynamicsMetrics\"}
output: log_request_total

Case # 5
input: sum(delta(log_request_total{className=~\".*ProductDashboardController\",methodName=~\"getDashboardConfig|updateMaintainers|addQuickLink|deleteQuickLink|addDependentMiddleware|addDependentService|updateErrorThreshold\"}[5m])) by (user_id)"
output: log_request_total

Case # 6
input: count_scalar(sum(log_query_request_total) by (user_id))
output: log_query_request_total

这是我在 Java 中尝试过的演示。但似乎我无法获得正确的pattern 来检索我上面提到的模式的确切答案。

如果可能,请分享一些想法。

public static void main(String... args) {
    String[] exprs = {"sum(log_query_task_cache_hit_rate_bucket)by(le)",
            "sum(log_search_by_service_total {service_name!~\"\"}) by (service_name, operator)",
            "log_request_total",
            " sum(delta(log_request_total[5m])) by (args, user_id)",
            "log_request_total{methodName=~\"getAppDynamicsGraphMetrics|getAppDynamicsMetrics\"}",
            "sum(delta(log_request_total{className=~\".*ProductDashboardController\",methodName=~\"getDashboardConfig|updateMaintainers|addQuickLink|deleteQuickLink|addDependentMiddleware|addDependentService|updateErrorThreshold\"}[5m])) by (user_id)",
            "sum(log_request_total{methodName=\"getInstanceNames\"}) by (user_id)",
            "sum(log_request_total{methodName=\"getVpcCardInfo\",user_id!~\"${user}\"}) by (envName)",
            "count_scalar(sum(log_query_request_total) by (user_id))",
            "avg(log_waiting_time_average) by (exported_tenant, exported_landscape)",
            "avg(task_processing_time_average{app=\"athena\"})",
            "avg(log_queue_time_average) by (log_type)",
            "sum(delta(product_dashboard_service_sum[2m]))",
            "ceil(delta(product_dashboard_service_count[5m]))]"
    };
    String[] expected = {
            "log_query_task_cache_hit_rate_bucket",
            "log_search_by_service_total",
            "log_request_total",
            "log_request_total",
            "log_request_total",
            "log_request_total",
            "log_request_total",
            "log_request_total",
            "log_query_request_total",
            "log_waiting_time_average",
            "task_processing_time_average",
            "log_queue_time_average",
            "product_dashboard_service_sum",
            "product_dashboard_service_count"
    };
    Pattern pattern = Pattern.compile(".*?\\(?([\\w|_]+)\\{?\\[?.*");
    testPattern(exprs, expected, pattern);
    pattern = Pattern.compile(".*\\(?([\\w|_]+)\\{?\\[?.*");
    testPattern(exprs, expected, pattern);
    pattern = Pattern.compile(".*?\\(?([\\w|_]+)\\{?\\[?.*");
    testPattern(exprs, expected, pattern);
}

private static void testPattern(String[] exprs, String[] expected, Pattern pattern) {
    System.out.println("\n********** Pattern Match Test *********\n");
    for (int i = 0; i < exprs.length; ++i) {
        String expr = exprs[i];
        Matcher matcher = pattern.matcher(expr);
        if (matcher.find()) {
            System.out.println("\nThe Original Expr: " + expr);
            System.out.println(String.format("Expected:\t %-40s Matched:\t %-40s", expected[i], matcher.group(1)));
        } else {
            System.out.println("expected: " + expected[i] + " not matched");
        }
    }
}

更新 2018-08-06

感谢 Bohemian 的帮助,它真的启发了我(因为我一直相信 regex 可以用干净的解决方案变魔术)。

后来,我发现exprs 比我预想的要复杂,如下所示:

Case # 7
input: topk(10,autoindex_online_consume_time_total_sum{app=~"$app", DTO_Name=~"$c_class"})
expected: autoindex_online_consume_time_total_sum
// to get the metric name: autoindex_online_consume_time_total_sum
// still I can make it work with small modifications as ^(?:\w+\()*(?:\d+,)*(\w+)

但以下一种甚至更多不同的复杂组合让我转向了可靠的方法:

Case # 8
input: sum(hue_mail_sent_attachment_bytes_total) by (app)  / sum(hue_mail_sent_mails_with_attachment_total) by (app)
Expected: [hue_mail_sent_attachment_bytes_total, hue_mail_sent_mails_with_attachment_total]

现在要复杂得多...甚至不可预测,因为无法控制来自用户的expr 输入。

所以我通过更可靠和简单的解决方案实现了相同的目标:

  1. 首先将 distinct 指标名称存储到数据库中;
  2. 当expr 出现时,使用contains(String s) 在内存中检查它;
  3. 仍然可能存在问题:如果某些指标名称包含其他指标名称,则会出现过度匹配;

【问题讨论】:

  • 这对于 RegEx 来说看起来太复杂了。对于这么复杂的东西,您可能需要一个词法分析器和一个 AST 生成器。

标签: java regex grafana prometheus regex-group


【解决方案1】:

此正则表达式捕获您在第 1 组中的目标

^(?:\w+\()*(\w+)

见live demo。

在java中,获取你的目标:

String metricName = input.replaceAll("^(?:\\w+\\()*(\\w+)", "$1");

【讨论】:

  • 哇,非常感谢@Bohemian。它是如此简洁和干净。 ^(?:\w+\()* 将匹配所有 method_name( 重复,并且在重复(零个或多个)之后它就是 => 我正在寻找的 METRIC_NAME。很好的解决方案;)
  • 我仍然需要对额外的空白进行一些小修改,以确保它始终有效。感谢您的帮助〜@Bohemian。 ^(?:\\s*\\w+\\s*\(\\s*)*\\s*(\w+)
猜你喜欢
  • 2020-06-15
  • 2019-12-02
  • 1970-01-01
  • 2019-12-07
  • 1970-01-01
  • 2011-05-11
  • 2019-08-09
  • 2021-12-24
  • 1970-01-01
相关资源
最近更新 更多