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, 1,
43 		    10, 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 		     1, 10, NULL, sec_tag_list_verify_none, sizeof(sec_tag_list_verify_none));
103 
104 HTTP_RESOURCE_DEFINE(index_html_gz_resource_https, test_https_service, "/metrics",
105 		     &dyn_resource_detail);
106 
107 #endif /* CONFIG_NET_SAMPLE_HTTPS_SERVICE */
108 
setup_tls(void)109 static void setup_tls(void)
110 {
111 #if defined(CONFIG_NET_SAMPLE_HTTPS_SERVICE)
112 #if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
113 	int err;
114 
115 #if defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC)
116 	err = tls_credential_add(HTTP_SERVER_CERTIFICATE_TAG, TLS_CREDENTIAL_CA_CERTIFICATE,
117 				 ca_certificate, sizeof(ca_certificate));
118 	if (err < 0) {
119 		LOG_ERR("Failed to register CA certificate: %d", err);
120 	}
121 #endif /* defined(CONFIG_NET_SAMPLE_CERTS_WITH_SC) */
122 
123 	err = tls_credential_add(HTTP_SERVER_CERTIFICATE_TAG, TLS_CREDENTIAL_SERVER_CERTIFICATE,
124 				 server_certificate, sizeof(server_certificate));
125 	if (err < 0) {
126 		LOG_ERR("Failed to register public certificate: %d", err);
127 	}
128 
129 	err = tls_credential_add(HTTP_SERVER_CERTIFICATE_TAG, TLS_CREDENTIAL_PRIVATE_KEY,
130 				 private_key, sizeof(private_key));
131 	if (err < 0) {
132 		LOG_ERR("Failed to register private key: %d", err);
133 	}
134 
135 #if defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
136 	err = tls_credential_add(PSK_TAG, TLS_CREDENTIAL_PSK, psk, sizeof(psk));
137 	if (err < 0) {
138 		LOG_ERR("Failed to register PSK: %d", err);
139 	}
140 
141 	err = tls_credential_add(PSK_TAG, TLS_CREDENTIAL_PSK_ID, psk_id, sizeof(psk_id) - 1);
142 	if (err < 0) {
143 		LOG_ERR("Failed to register PSK ID: %d", err);
144 	}
145 #endif /* defined(CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) */
146 #endif /* defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS) */
147 #endif /* defined(CONFIG_NET_SAMPLE_HTTPS_SERVICE) */
148 }
149 
150 PROMETHEUS_COUNTER_DEFINE(http_request_counter, "HTTP request counter",
151 			  ({ .key = "http_request", .value = "request_count" }), NULL);
152 
153 PROMETHEUS_COLLECTOR_DEFINE(test_collector);
154 
main(void)155 int main(void)
156 {
157 	/* Create a mock collector with different types of metrics */
158 	prom_context.collector = &test_collector;
159 
160 	prom_context.counter = &http_request_counter;
161 	prometheus_counter_inc(prom_context.counter);
162 
163 	prometheus_collector_register_metric(prom_context.collector, &prom_context.counter->base);
164 
165 #if defined(CONFIG_NET_STATISTICS_VIA_PROMETHEUS)
166 	(void)init_stats(prom_context.counter);
167 #endif
168 
169 	setup_tls();
170 
171 	http_server_start();
172 
173 	return 0;
174 }
175