Aclk proxy connect log (#21789)
* Improve ACLK logging if proxy is used - Enhance logging if proxy is used (with or without credentials) * - Replace inline proxy display formatting with `aclk_proxy_get_display` helper function. - Simplify and unify proxy display construction in ACLK logging. - Adjust key name in JSON payload from `aclk-proxy` to `aclk_proxy`. * Refactor proxy display construction with new `aclk_proxy_get_full_display` helper function. * Fix incorrect proxy username extraction by replacing `strchr` with `strrchr` in `aclk_proxy_get_display`.
Stelios Fragkakis committed
Feb 24, 2026 at 12:44 UTC
b829cb3ae2bd2ff88609a990cdce7732de85fb94
7 files changed
+157
-20
src/aclk/aclk.c
+11
-5
@@ -1096,11 +1096,14 @@ char *aclk_state(void)
1096
buffer_strcat(wb, "No\n");
1097
else {
1098
const char *cloud_base_url = cloud_config_url_get();
1099
- char *aclk_proxy = (char *)aclk_get_proxy(NULL, true);
1099
+
1100
+ char proxy_display[512];
1101
+ aclk_proxy_get_full_display(proxy_display, sizeof(proxy_display));
1102
+
1103
usec_t latency = __atomic_load_n(&publish_latency, __ATOMIC_RELAXED);
1104
char latency_str[64];
1105
duration_snprintf(latency_str, sizeof(latency_str), (int64_t) latency, "us", true);
1103
- buffer_sprintf(wb, "Yes\nClaimed Id: %s\nCloud URL: %s\nACLK Proxy: %s\nPublish Latency: %s\n", claim_id.str, cloud_base_url ? cloud_base_url : "null", aclk_proxy ? aclk_proxy : "none", latency_str);
1106
+ buffer_sprintf(wb, "Yes\nClaimed Id: %s\nCloud URL: %s\nACLK Proxy: %s\nPublish Latency: %s\n", claim_id.str, cloud_base_url ? cloud_base_url : "null", proxy_display, latency_str);
1107
}
1108
1109
bool aclk_is_online = aclk_online();
@@ -1244,9 +1247,12 @@ char *aclk_state_json(void)
1247
tmp = cloud_base_url ? json_object_new_string(cloud_base_url) : NULL;
1248
json_object_object_add(msg, "cloud-url", tmp);
1249
1247
- char *aclk_proxy = (char *)aclk_get_proxy(NULL, true);
1248
- tmp = aclk_proxy ? json_object_new_string(aclk_proxy) : NULL;
1249
- json_object_object_add(msg, "aclk_proxy", tmp);
1250
+ {
1251
+ char proxy_display[512];
1252
+ aclk_proxy_get_full_display(proxy_display, sizeof(proxy_display));
1253
+ tmp = json_object_new_string(proxy_display);
1254
+ json_object_object_add(msg, "aclk_proxy", tmp);
1255
+ }
1256
1257
usec_t latency = __atomic_load_n(&publish_latency, __ATOMIC_RELAXED);
1258
tmp =json_object_new_int64((int64_t) latency);
src/aclk/aclk_proxy.c
+76
-2
@@ -76,6 +76,19 @@ static inline void safe_log_proxy_error(char *str, const char *proxy)
76
freez(log);
77
}
78
79
+// helper to extract "http://host:port" from a proxy URL, skipping credentials
80
+void aclk_proxy_get_display(char *buf, size_t buflen, const char *proxy, ACLK_PROXY_TYPE type)
81
+{
82
+ const char *at = strrchr(proxy, '@');
83
+ const char *host_start = at ? at + 1 : proxy;
84
+ const char *sep = strstr(proxy, ACLK_PROXY_PROTO_ADDR_SEPARATOR);
85
+ if (!at && sep)
86
+ host_start = sep + strlen(ACLK_PROXY_PROTO_ADDR_SEPARATOR);
87
+ snprintfz(buf, buflen, "%s%s", aclk_proxy_type_to_url(type), host_start);
88
+}
89
+
90
+static const char *proxy_source = NULL;
91
+
92
static inline int check_http_environment(const char **proxy)
93
{
94
const char *var = "http_proxy";
@@ -90,6 +103,15 @@ static inline int check_http_environment(const char **proxy)
103
104
if (aclk_verify_proxy(tmp) == PROXY_TYPE_HTTP) {
105
*proxy = tmp;
106
+ char display[512];
107
+ aclk_proxy_get_display(display, sizeof(display), tmp, PROXY_TYPE_HTTP);
108
+ char source_buf[256];
109
+ snprintfz(source_buf, sizeof(source_buf), "environment variable '%s'", var);
110
+ freez((void *)proxy_source);
111
+ proxy_source = strdupz(source_buf);
112
+ nd_log(NDLS_DAEMON, NDLP_INFO,
113
+ "ACLK: using HTTP proxy %s (%s, from %s)",
114
+ display, strchr(tmp, '@') ? "with credentials" : "without credentials", proxy_source);
115
return 0;
116
}
117
@@ -109,14 +131,28 @@ const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type)
131
132
*type = PROXY_DISABLED;
133
112
- if (!proxy || !*proxy || strcmp(proxy, "none") == 0)
134
+ if (!proxy || !*proxy || strcmp(proxy, "none") == 0) {
135
+ nd_log(NDLS_DAEMON, NDLP_INFO,
136
+ "ACLK: proxy is %s, will connect directly without proxy.",
137
+ (!proxy || !*proxy) ? "not configured" : "set to 'none'");
138
+ freez((void *)proxy_source);
139
+ proxy_source = NULL;
140
return proxy;
141
+ }
142
143
if (strcmp(proxy, ACLK_PROXY_ENV) == 0) {
144
if (check_http_environment(&proxy) == 0)
145
*type = PROXY_TYPE_HTTP;
118
- else
146
+ else {
147
+ if (cloud_config_proxy_is_explicitly_set())
148
+ nd_log(NDLS_DAEMON, NDLP_WARNING,
149
+ "ACLK: proxy is explicitly set to 'env' but neither 'http_proxy' nor 'https_proxy'"
150
+ " environment variables are set. Will connect directly without proxy.");
151
+
152
+ freez((void *)proxy_source);
153
+ proxy_source = NULL;
154
proxy = NULL;
155
+ }
156
return proxy;
157
}
158
@@ -128,6 +164,21 @@ const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type)
164
"Config var \"" ACLK_PROXY_CONFIG_VAR
165
"\" defined but of unknown format. Supported syntax: \"socks5[h]://[user:pass@]host:ip\".",
166
proxy);
167
+ freez((void *)proxy_source);
168
+ proxy_source = NULL;
169
+ }
170
+ else {
171
+ const char *src = cloud_config_proxy_source_get();
172
+ freez((void *)proxy_source);
173
+ proxy_source = src ? strdupz(src) : NULL;
174
+ char display[512];
175
+ aclk_proxy_get_display(display, sizeof(display), proxy, *type);
176
+ nd_log(NDLS_DAEMON, NDLP_INFO,
177
+ "ACLK: using %s proxy %s (%s, from %s)",
178
+ *type == PROXY_TYPE_HTTP ? "HTTP" : "SOCKS5",
179
+ display,
180
+ strchr(proxy, '@') ? "with credentials" : "without credentials",
181
+ proxy_source);
182
}
183
184
return proxy;
@@ -156,3 +207,26 @@ const char *aclk_get_proxy(ACLK_PROXY_TYPE *return_type, bool for_logging)
207
*return_type = proxy_type;
208
return for_logging ? safe_proxy : proxy;
209
}
210
+
211
+const char *aclk_get_proxy_source(void) {
212
+ return proxy_source;
213
+}
214
+
215
+void aclk_proxy_get_full_display(char *buf, size_t buflen) {
216
+ ACLK_PROXY_TYPE proxy_type;
217
+ const char *proxy_str = aclk_get_proxy(&proxy_type, false);
218
+
219
+ if (proxy_type == PROXY_DISABLED || proxy_type == PROXY_NOT_SET || !proxy_str) {
220
+ snprintfz(buf, buflen, "none");
221
+ return;
222
+ }
223
+
224
+ char host_display[256];
225
+ aclk_proxy_get_display(host_display, sizeof(host_display), proxy_str, proxy_type);
226
+
227
+ const char *source = aclk_get_proxy_source();
228
+ snprintfz(buf, buflen, "%s (%s, from %s)",
229
+ host_display,
230
+ strchr(proxy_str, '@') ? "with credentials" : "without credentials",
231
+ source ? source : "unknown");
232
+}
src/aclk/aclk_proxy.h
+11
@@ -17,5 +17,16 @@ ACLK_PROXY_TYPE aclk_verify_proxy(const char *string);
17
const char *aclk_lws_wss_get_proxy_setting(ACLK_PROXY_TYPE *type);
18
void safe_log_proxy_censor(char *proxy);
19
const char *aclk_get_proxy(ACLK_PROXY_TYPE *type, bool for_logging);
20
+const char *aclk_get_proxy_source(void);
21
+void aclk_proxy_get_display(char *buf, size_t buflen, const char *proxy, ACLK_PROXY_TYPE type);
22
+void aclk_proxy_get_full_display(char *buf, size_t buflen);
23
+
24
+static inline const char *aclk_proxy_type_to_url(ACLK_PROXY_TYPE type) {
25
+ switch (type) {
26
+ case PROXY_TYPE_HTTP: return "http://";
27
+ case PROXY_TYPE_SOCKS5: return "socks5://";
28
+ default: return "";
29
+ }
30
+}
31
32
#endif /* ACLK_PROXY_H */
src/aclk/https_client.c
+30
-8
@@ -763,16 +763,28 @@ https_client_resp_t https_request(https_req_t *request, https_req_response_t *re
763
764
bool proxy_used = (request->proxy_host != NULL);
765
766
+ // extract protocol prefix from proxy URL for logging
767
+ const char *proxy_proto = "";
768
+ char proto_buf[16];
769
+ if (proxy_used && request->proxy) {
770
+ const char *sep = strstr(request->proxy, "://");
771
+ if (sep) {
772
+ size_t len = (size_t)(sep - request->proxy) + 3;
773
+ if (len < sizeof(proto_buf)) {
774
+ memcpy(proto_buf, request->proxy, len);
775
+ proto_buf[len] = '\0';
776
+ proxy_proto = proto_buf;
777
+ }
778
+ }
779
+ }
780
+
781
// assume no proxy
782
const char *connect_host;
783
int connect_port;
769
- const char *proxy_used_str = " (no proxy)";
770
-
784
785
if (unlikely(proxy_used)) {
786
connect_host = request->proxy_host;
787
connect_port = request->proxy_port;
775
- proxy_used_str = request->proxy;
788
} else {
789
connect_host = request->host;
790
connect_port = request->port;
@@ -790,9 +802,14 @@ https_client_resp_t https_request(https_req_t *request, https_req_response_t *re
802
803
snprintfz(connect_port_str, PORT_STR_MAX_BYTES, "%d", connect_port);
804
793
- nd_log_daemon(NDLP_INFO, "ACLK: Connecting to %s:%d%s%s",
794
- request->host, request->port,
795
- proxy_used ? " via proxy " : "", proxy_used_str);
805
+ if (proxy_used)
806
+ nd_log_daemon(NDLP_INFO, "ACLK: connecting to %s:%d via proxy %s%s:%d%s",
807
+ request->host, request->port,
808
+ proxy_proto, request->proxy_host, request->proxy_port,
809
+ request->proxy_username ? " (with credentials)" : " (without credentials)");
810
+ else
811
+ nd_log_daemon(NDLP_INFO, "ACLK: connecting to %s:%d (no proxy)",
812
+ request->host, request->port);
813
814
struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
815
ctx->sock = connect_to_this_ip46(IPPROTO_TCP, SOCK_STREAM, connect_host, 0, connect_port_str, &timeout, fallback_ipv4);
@@ -823,13 +840,18 @@ https_client_resp_t https_request(https_req_t *request, https_req_response_t *re
840
ctx->request = &req;
841
rc = handle_http_request(ctx);
842
if (rc != HTTPS_CLIENT_RESP_OK) {
826
- netdata_log_error("ACLK: failed to CONNECT with proxy");
843
+ netdata_log_error("ACLK: failed to CONNECT via proxy %s%s:%d to %s:%d",
844
+ proxy_proto, request->proxy_host, request->proxy_port,
845
+ request->host, request->port);
846
http_parse_ctx_destroy(&ctx->parse_ctx);
847
goto exit_sock;
848
}
849
if (ctx->parse_ctx.http_code != 200) {
850
rc = HTTPS_CLIENT_RESP_PROXY_NOT_200;
832
- netdata_log_error("ACLK: proxy didn't return 200 OK (got %d)", ctx->parse_ctx.http_code);
851
+ netdata_log_error("ACLK: proxy %s%s:%d returned HTTP %d (expected 200) for CONNECT to %s:%d",
852
+ proxy_proto, request->proxy_host, request->proxy_port,
853
+ ctx->parse_ctx.http_code,
854
+ request->host, request->port);
855
http_parse_ctx_destroy(&ctx->parse_ctx);
856
goto exit_sock;
857
}
src/aclk/mqtt_websockets/mqtt_wss_client.c
+10
-5
@@ -479,11 +479,16 @@ int mqtt_wss_connect(
479
char port_str[16];
480
snprintf(port_str, sizeof(port_str) -1, "%d", client->port);
481
482
- bool proxy_used = (proxy && proxy->proxy_destination != NULL);
483
-
484
- nd_log_daemon(NDLP_INFO, "ACLK: Connecting to %s:%d%s%s",
485
- client->target_host, client->target_port,
486
- proxy_used ? " via proxy " : " (no proxy)", proxy_used ? proxy->proxy_destination : "");
482
+ if (proxy && proxy->type != MQTT_WSS_DIRECT) {
483
+ const char *proxy_proto = (proxy->type == MQTT_WSS_PROXY_HTTP) ? "http://" : "socks5://";
484
+ nd_log_daemon(NDLP_INFO, "ACLK: connecting to %s:%d via proxy %s%s:%d%s",
485
+ client->target_host, client->target_port,
486
+ proxy_proto, client->host, client->port,
487
+ client->proxy_uname ? " (with credentials)" : " (without credentials)");
488
+ }
489
+ else
490
+ nd_log_daemon(NDLP_INFO, "ACLK: connecting to %s:%d (no proxy)",
491
+ client->target_host, client->target_port);
492
493
struct timeval timeout = { .tv_sec = 10, .tv_usec = 0 };
494
int fd = connect_to_this_ip46(IPPROTO_TCP, SOCK_STREAM, client->host, 0, port_str, &timeout, fallback_ipv4);
src/claim/claim.h
+2
@@ -30,6 +30,8 @@ CLOUD_STATUS claim_reload_and_wait_online(void);
30
const char *cloud_config_url_get(void);
31
void cloud_config_url_set(const char *url);
32
const char *cloud_config_proxy_get(void);
33
+const char *cloud_config_proxy_source_get(void);
34
+bool cloud_config_proxy_is_explicitly_set(void);
35
bool cloud_config_insecure_get(void);
36
37
#endif //NETDATA_CLAIM_H
src/claim/cloud-conf.c
+17
@@ -16,6 +16,9 @@ void cloud_config_url_set(const char *url) {
16
inicfg_set(&cloud_config, CONFIG_SECTION_GLOBAL, "url", url);
17
}
18
19
+static const char *cloud_config_proxy_source = NULL;
20
+static bool cloud_config_proxy_explicitly_set = false;
21
+
22
const char *cloud_config_proxy_get(void) {
23
// load cloud.conf or internal default
24
const char *proxy = inicfg_get(&cloud_config, CONFIG_SECTION_GLOBAL, "proxy", "env");
@@ -28,15 +31,26 @@ const char *cloud_config_proxy_get(void) {
31
32
// update cloud.conf
33
proxy = inicfg_set(&cloud_config, CONFIG_SECTION_GLOBAL, "proxy", proxy);
34
+ cloud_config_proxy_source = "netdata.conf [cloud]";
35
+ cloud_config_proxy_explicitly_set = true;
36
}
37
else {
38
// set in netdata.conf the proxy of cloud.conf
39
inicfg_set(&netdata_config, CONFIG_SECTION_CLOUD, "proxy", proxy);
40
+ cloud_config_proxy_source = "cloud.conf";
41
}
42
43
return proxy;
44
}
45
46
+const char *cloud_config_proxy_source_get(void) {
47
+ return cloud_config_proxy_source;
48
+}
49
+
50
+bool cloud_config_proxy_is_explicitly_set(void) {
51
+ return cloud_config_proxy_explicitly_set;
52
+}
53
+
54
bool cloud_config_insecure_get(void) {
55
// load it from cloud.conf or use internal default
56
return inicfg_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "insecure", CONFIG_BOOLEAN_NO);
@@ -70,6 +84,9 @@ void cloud_conf_load(int silent) {
84
CONFIG_SECTION_GLOBAL, "cloud base url",
85
CONFIG_SECTION_GLOBAL, "url");
86
87
+ // check if proxy was explicitly set in cloud.conf before defaults overwrite it
88
+ cloud_config_proxy_explicitly_set = inicfg_exists(&cloud_config, CONFIG_SECTION_GLOBAL, "proxy");
89
+
90
cloud_conf_load_defaults();
91
}
92