1 /*
2 * Copyright (c) 2024 Nordic Semiconductor
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_DECLARE(main, LOG_LEVEL_DBG);
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/net/tls_credentials.h>
13 #include <zephyr/net/http/server.h>
14 #include <zephyr/net/http/service.h>
15 #include <zephyr/net/net_if.h>
16 #include <zephyr/net/net_ip.h>
17
18 #include <zephyr/net/prometheus/formatter.h>
19 #include <zephyr/net/prometheus/collector.h>
20 #include <zephyr/net/prometheus/counter.h>
21 #include <zephyr/net/prometheus/gauge.h>
22 #include <zephyr/net/prometheus/histogram.h>
23 #include <zephyr/net/prometheus/summary.h>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 extern struct http_service_desc test_http_service;
30
31 static struct prometheus_counter *http_request_counter;
32 static struct prometheus_collector *stats_collector;
33 static struct prometheus_collector_walk_context walk_ctx;
34
stats_handler(struct http_client_ctx * client,enum http_data_status status,const struct http_request_ctx * request_ctx,struct http_response_ctx * response_ctx,void * user_data)35 static int stats_handler(struct http_client_ctx *client, enum http_data_status status,
36 const struct http_request_ctx *request_ctx,
37 struct http_response_ctx *response_ctx, void *user_data)
38 {
39 int ret;
40 static uint8_t prom_buffer[1024];
41
42 if (status == HTTP_SERVER_DATA_FINAL) {
43
44 /* incrase counter per request */
45 prometheus_counter_inc(http_request_counter);
46
47 (void)memset(prom_buffer, 0, sizeof(prom_buffer));
48
49 ret = prometheus_collector_walk_metrics(user_data,
50 prom_buffer,
51 sizeof(prom_buffer));
52 if (ret < 0 && ret != -EAGAIN) {
53 LOG_ERR("Cannot format exposition data (%d)", ret);
54 return ret;
55 }
56
57 response_ctx->body = prom_buffer;
58 response_ctx->body_len = strlen(prom_buffer);
59
60 if (ret == 0) {
61 response_ctx->final_chunk = true;
62 ret = prometheus_collector_walk_init(&walk_ctx, stats_collector);
63 if (ret < 0) {
64 LOG_ERR("Cannot initialize walk context (%d)", ret);
65 }
66 }
67 }
68
69 return 0;
70 }
71
72 struct http_resource_detail_dynamic stats_resource_detail = {
73 .common = {
74 .type = HTTP_RESOURCE_TYPE_DYNAMIC,
75 .bitmask_of_supported_http_methods = BIT(HTTP_GET),
76 .content_type = "text/plain",
77 },
78 .cb = stats_handler,
79 .user_data = &walk_ctx,
80 };
81
82 HTTP_RESOURCE_DEFINE(stats_resource, test_http_service, "/statistics", &stats_resource_detail);
83
init_stats(struct prometheus_counter * counter)84 int init_stats(struct prometheus_counter *counter)
85 {
86 /* Use a collector from default network interface */
87 stats_collector = net_if_get_default()->collector;
88 if (stats_collector == NULL) {
89 LOG_ERR("Cannot get collector from default network interface");
90 return -EINVAL;
91 }
92
93 (void)prometheus_collector_walk_init(&walk_ctx, stats_collector);
94
95 http_request_counter = counter;
96
97 return 0;
98 }
99