1 /*
2  * Copyright (c) 2024 Mustafa Abdullah Kus, Sparse Technology
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/drivers/sensor.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/net/tls_credentials.h>
11 #include <zephyr/net/http/server.h>
12 #include <zephyr/net/http/service.h>
13 #include <zephyr/net/net_ip.h>
14 #include <zephyr/net/socket.h>
15 
16 #include <zephyr/net/prometheus/formatter.h>
17 #include <zephyr/net/prometheus/collector.h>
18 #include <zephyr/net/prometheus/counter.h>
19 #include <zephyr/net/prometheus/gauge.h>
20 #include <zephyr/net/prometheus/histogram.h>
21 #include <zephyr/net/prometheus/summary.h>
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <zephyr/logging/log.h>
28 LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);
29 
30 extern int init_stats(struct prometheus_counter *counter);
31 
32 struct app_context {
33 
34 	struct prometheus_collector *collector;
35 
36 	struct prometheus_counter *counter;
37 
38 } prom_context;
39 
40 #if defined(CONFIG_NET_SAMPLE_HTTP_SERVICE)
41 static uint16_t test_http_service_port = CONFIG_NET_SAMPLE_HTTP_SERVER_SERVICE_PORT;
42 HTTP_SERVICE_DEFINE(test_http_service, CONFIG_NET_CONFIG_MY_IPV4_ADDR, &test_http_service_port,
43 		    CONFIG_HTTP_SERVER_MAX_CLIENTS, 10, NULL, NULL, NULL);
44 
dyn_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)45 static int dyn_handler(struct http_client_ctx *client, enum http_data_status status,
46 		       const struct http_request_ctx *request_ctx,
47 		       struct http_response_ctx *response_ctx, void *user_data)
48 {
49 	int ret;
50 	static uint8_t prom_buffer[256];
51 
52 	if (status == HTTP_SERVER_DATA_FINAL) {
53 
54 		/* incrase counter per request */
55 		prometheus_counter_inc(prom_context.counter);
56 
57 		/* clear buffer */
58 		(void)memset(prom_buffer, 0, sizeof(prom_buffer));
59 
60 		/* format exposition data */
61 		ret = prometheus_format_exposition(prom_context.collector, prom_buffer,
62 						   sizeof(prom_buffer));
63 		if (ret < 0) {
64 			LOG_ERR("Cannot format exposition data (%d)", ret);
65 			return ret;
66 		}
67 
68 		response_ctx->body = prom_buffer;
69 		response_ctx->body_len = strlen(prom_buffer);
70 		response_ctx->final_chunk = true;
71 	}
72 
73 	return 0;
74 }
75 
76 struct http_resource_detail_dynamic dyn_resource_detail = {
77 	.common = {
78 			.type = HTTP_RESOURCE_TYPE_DYNAMIC,
79 			.bitmask_of_supported_http_methods = BIT(HTTP_GET),
80 			.content_type = "text/plain",
81 		},
82 	.cb = dyn_handler,
83 	.user_data = NULL,
84 };
85 
86 HTTP_RESOURCE_DEFINE(dyn_resource, test_http_service, "/metrics", &dyn_resource_detail);
87 
88 #endif /* CONFIG_NET_SAMPLE_HTTP_SERVICE */
89 
90 #if defined(CONFIG_NET_SAMPLE_HTTPS_SERVICE)
91 #include "certificate.h"
92 
93 const sec_tag_t sec_tag_list_verify_none[] = {
94 	HTTP_SERVER_CERTIFICATE_TAG,
95 #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
96 	PSK_TAG,
97 #endif
98 };
99 
100 static uint16_t test_https_service_port = CONFIG_NET_SAMPLE_HTTPS_SERVER_SERVICE_PORT;
101 HTTPS_SERVICE_DEFINE(test_https_service, CONFIG_NET_CONFIG_MY_IPV4_ADDR, &test_https_service_port,
102 		     CONFIG_HTTP_SERVER_MAX_CLIENTS, 10, NULL, NULL, NULL, sec_tag_list_verify_none,
103 		     sizeof(sec_tag_list_verify_none));
104 
105 HTTP_RESOURCE_DEFINE(index_html_gz_resource_https, test_https_service, "/metrics",
106 		     &dyn_resource_detail);
107 
108 #endif /* CONFIG_NET_SAMPLE_HTTPS_SERVICE */
109 
setup_tls(void)110 static void setup_tls(void)
111 {
112 #if defined(CONFIG_NET_SAMPLE_HTTPS_SERVICE)
113 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
114 	int err;
115 
116 #if defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC)
117 	err = tls_credential_add(HTTP_SERVER_CERTIFICATE_TAG, TLS_CREDENTIAL_CA_CERTIFICATE,
118 				 ca_certificate, sizeof(ca_certificate));
119 	if (err < 0) {
120 		LOG_ERR("Failed to register CA certificate: %d", err);
121 	}
122 #endif /* defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) */
123 
124 	err = tls_credential_add(HTTP_SERVER_CERTIFICATE_TAG, TLS_CREDENTIAL_PUBLIC_CERTIFICATE,
125 				 server_certificate, sizeof(server_certificate));
126 	if (err < 0) {
127 		LOG_ERR("Failed to register public certificate: %d", err);
128 	}
129 
130 	err = tls_credential_add(HTTP_SERVER_CERTIFICATE_TAG, TLS_CREDENTIAL_PRIVATE_KEY,
131 				 private_key, sizeof(private_key));
132 	if (err < 0) {
133 		LOG_ERR("Failed to register private key: %d", err);
134 	}
135 
136 #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
137 	err = tls_credential_add(PSK_TAG, TLS_CREDENTIAL_PSK, psk, sizeof(psk));
138 	if (err < 0) {
139 		LOG_ERR("Failed to register PSK: %d", err);
140 	}
141 
142 	err = tls_credential_add(PSK_TAG, TLS_CREDENTIAL_PSK_ID, psk_id, sizeof(psk_id) - 1);
143 	if (err < 0) {
144 		LOG_ERR("Failed to register PSK ID: %d", err);
145 	}
146 #endif /* defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) */
147 #endif /* defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) */
148 #endif /* defined(CONFIG_NET_SAMPLE_HTTPS_SERVICE) */
149 }
150 
151 PROMETHEUS_COUNTER_DEFINE(http_request_counter, "HTTP request counter",
152 			  ({ .key = "http_request", .value = "request_count" }), NULL);
153 
154 PROMETHEUS_COLLECTOR_DEFINE(test_collector);
155 
main(void)156 int main(void)
157 {
158 	/* Create a mock collector with different types of metrics */
159 	prom_context.collector = &test_collector;
160 
161 	prom_context.counter = &http_request_counter;
162 	prometheus_counter_inc(prom_context.counter);
163 
164 	prometheus_collector_register_metric(prom_context.collector, &prom_context.counter->base);
165 
166 #if defined(CONFIG_NET_STATISTICS_VIA_PROMETHEUS)
167 	(void)init_stats(prom_context.counter);
168 #endif
169 
170 	setup_tls();
171 
172 	http_server_start();
173 
174 	return 0;
175 }
176