netdata now detects current timezone and reports it to the dashboard; it also streams it to upstream netdata servers; #2698
Costa Tsaousis (ktsaou) committed
Oct 8, 2017 at 17:35 UTC
011b3174743d6d55922537532fb33fbb6d80f395
7 files changed
+117
-10
src/common.c
+1
@@ -17,6 +17,7 @@ char *netdata_configured_cache_dir = NULL;
17
char *netdata_configured_varlib_dir = NULL;
18
char *netdata_configured_home_dir = NULL;
19
char *netdata_configured_host_prefix = NULL;
20
+char *netdata_configured_timezone = NULL;
21
22
int enable_ksm = 1;
23
src/common.h
+1
@@ -238,6 +238,7 @@ extern char *netdata_configured_cache_dir;
238
extern char *netdata_configured_varlib_dir;
239
extern char *netdata_configured_home_dir;
240
extern char *netdata_configured_host_prefix;
241
+extern char *netdata_configured_timezone;
242
243
extern void netdata_fix_chart_id(char *s);
244
extern void netdata_fix_chart_name(char *s);
src/main.c
+82
-5
@@ -496,6 +496,87 @@ static void get_netdata_configured_variables() {
496
get_system_pid_max();
497
}
498
499
+static void get_system_timezone(void) {
500
+ // avoid flood calls to stat(/etc/localtime)
501
+ // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
502
+ const char *tz = getenv("TZ");
503
+ if(!tz || !*tz)
504
+ setenv("TZ", config_get(CONFIG_SECTION_GLOBAL, "TZ environment variable", ":/etc/localtime"), 0);
505
+
506
+ char buffer[FILENAME_MAX + 1];
507
+ const char *timezone = NULL;
508
+ ssize_t ret;
509
+
510
+ // use the TZ variable
511
+ if(tz && *tz && *tz != ':') {
512
+ timezone = tz;
513
+ // info("TIMEZONE: using TZ variable '%s'", timezone);
514
+ }
515
+
516
+ // use the contents of /etc/timezone
517
+ if(!timezone && !read_file("/etc/timezone", buffer, FILENAME_MAX)) {
518
+ timezone = buffer;
519
+ // info("TIMEZONE: using the contents of /etc/timezone: '%s'", timezone);
520
+ }
521
+
522
+ // read the link /etc/localtime
523
+ if(!timezone && (ret = readlink("/etc/localtime", buffer, FILENAME_MAX)) > 0) {
524
+ buffer[ret] = '\0';
525
+
526
+ char *cmp = "/usr/share/zoneinfo/";
527
+ size_t cmp_len = strlen(cmp);
528
+
529
+ if(!strncmp(buffer, cmp, cmp_len) && buffer[cmp_len]) {
530
+ timezone = &buffer[cmp_len];
531
+ // info("TIMEZONE: using the link of /etc/localtime: '%s'", timezone);
532
+ }
533
+ }
534
+
535
+ // find the timezone from strftime()
536
+ if(!timezone) {
537
+ time_t t;
538
+ struct tm *tmp, tmbuf;
539
+
540
+ t = now_realtime_sec();
541
+ tmp = localtime_r(&t, &tmbuf);
542
+
543
+ if (tmp != NULL) {
544
+ if(strftime(buffer, FILENAME_MAX, "%Z", tmp) == 0)
545
+ buffer[0] = '\0';
546
+ else {
547
+ buffer[FILENAME_MAX] = '\0';
548
+ timezone = buffer;
549
+ // info("TIMEZONE: using strftime(): '%s'", timezone);
550
+ }
551
+ }
552
+ }
553
+
554
+ if(timezone && *timezone) {
555
+ // make sure it does not have illegal characters
556
+ // info("TIMEZONE: fixing '%s'", timezone);
557
+
558
+ char tmp[strlen(timezone) + 1];
559
+ char *d = tmp;
560
+ *d = '\0';
561
+
562
+ while(*timezone) {
563
+ if(isalnum(*timezone) || *timezone == '_' || *timezone == '/')
564
+ *d++ = *timezone++;
565
+ else
566
+ timezone++;
567
+ }
568
+ *d = '\0';
569
+ strcpy(buffer, tmp);
570
+ timezone = buffer;
571
+ // info("TIMEZONE: fixed as '%s'", timezone);
572
+ }
573
+
574
+ if(!timezone || !*timezone)
575
+ timezone = "unknown";
576
+
577
+ netdata_configured_timezone = config_get(CONFIG_SECTION_GLOBAL, "timezone", timezone);
578
+}
579
+
580
void set_global_environment() {
581
{
582
char b[16];
@@ -513,11 +594,7 @@ void set_global_environment() {
594
setenv("HOME" , verify_required_directory(netdata_configured_home_dir), 1);
595
setenv("NETDATA_HOST_PREFIX", netdata_configured_host_prefix, 1);
596
516
- // avoid flood calls to stat(/etc/localtime)
517
- // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
518
- const char *tz = getenv("TZ");
519
- if(!tz || !*tz)
520
- setenv("TZ", config_get(CONFIG_SECTION_GLOBAL, "TZ environment variable", ":/etc/localtime"), 0);
597
+ get_system_timezone();
598
599
// set the path we need
600
char path[1024 + 1], *p = getenv("PATH");
src/rrd.h
+2
@@ -410,6 +410,7 @@ struct rrdhost {
410
411
const char *os; // the O/S type of the host
412
const char *tags; // tags for this host
413
+ const char *timezone; // the timezone of the host
414
415
uint32_t flags; // flags about this RRDHOST
416
@@ -541,6 +542,7 @@ extern RRDHOST *rrdhost_find_or_create(
542
, const char *registry_hostname
543
, const char *guid
544
, const char *os
545
+ , const char *timezone
546
, const char *tags
547
, int update_every
548
, long history
src/rrd2json.c
+2
@@ -92,6 +92,7 @@ void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb) {
92
"\t\"hostname\": \"%s\""
93
",\n\t\"version\": \"%s\""
94
",\n\t\"os\": \"%s\""
95
+ ",\n\t\"timezone\": \"%s\""
96
",\n\t\"update_every\": %d"
97
",\n\t\"history\": %ld"
98
",\n\t\"custom_info\": \"%s\""
@@ -99,6 +100,7 @@ void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb) {
100
, host->hostname
101
, program_version
102
, host->os
103
+ , host->timezone
104
, host->rrd_update_every
105
, host->rrd_history_entries
106
, custom_dashboard_info_js_filename
src/rrdhost.c
+18
-1
@@ -86,6 +86,15 @@ static inline void rrdhost_init_os(RRDHOST *host, const char *os) {
86
freez(old);
87
}
88
89
+static inline void rrdhost_init_timezone(RRDHOST *host, const char *timezone) {
90
+ if(host->timezone && timezone && !strcmp(host->timezone, timezone))
91
+ return;
92
+
93
+ void *old = (void *)host->timezone;
94
+ host->timezone = strdupz((timezone && *timezone)?timezone:"unknown");
95
+ freez(old);
96
+}
97
+
98
static inline void rrdhost_init_machine_guid(RRDHOST *host, const char *machine_guid) {
99
strncpy(host->machine_guid, machine_guid, GUID_LEN);
100
host->machine_guid[GUID_LEN] = '\0';
@@ -100,6 +109,7 @@ RRDHOST *rrdhost_create(const char *hostname,
109
const char *registry_hostname,
110
const char *guid,
111
const char *os,
112
+ const char *timezone,
113
const char *tags,
114
int update_every,
115
long entries,
@@ -134,6 +144,7 @@ RRDHOST *rrdhost_create(const char *hostname,
144
rrdhost_init_hostname(host, hostname);
145
rrdhost_init_machine_guid(host, guid);
146
rrdhost_init_os(host, os);
147
+ rrdhost_init_timezone(host, timezone);
148
rrdhost_init_tags(host, tags);
149
host->registry_hostname = strdupz((registry_hostname && *registry_hostname)?registry_hostname:hostname);
150
@@ -251,7 +262,8 @@ RRDHOST *rrdhost_create(const char *hostname,
262
}
263
else {
264
info("Host '%s' (at registry as '%s') with guid '%s' initialized"
254
- ", os %s"
265
+ ", os '%s'"
266
+ ", timezone '%s'"
267
", tags '%s'"
268
", update every %d"
269
", memory mode %s"
@@ -268,6 +280,7 @@ RRDHOST *rrdhost_create(const char *hostname,
280
, host->registry_hostname
281
, host->machine_guid
282
, host->os
283
+ , host->timezone
284
, (host->tags)?host->tags:""
285
, host->rrd_update_every
286
, rrd_memory_mode_name(host->rrd_memory_mode)
@@ -294,6 +307,7 @@ RRDHOST *rrdhost_find_or_create(
307
, const char *registry_hostname
308
, const char *guid
309
, const char *os
310
+ , const char *timezone
311
, const char *tags
312
, int update_every
313
, long history
@@ -313,6 +327,7 @@ RRDHOST *rrdhost_find_or_create(
327
, registry_hostname
328
, guid
329
, os
330
+ , timezone
331
, tags
332
, update_every
333
, history
@@ -404,6 +419,7 @@ void rrd_init(char *hostname) {
419
, registry_get_this_machine_hostname()
420
, registry_get_this_machine_guid()
421
, os_type
422
+ , netdata_configured_timezone
423
, config_get(CONFIG_SECTION_BACKEND, "host tags", "")
424
, default_rrd_update_every
425
, default_rrd_history_entries
@@ -510,6 +526,7 @@ void rrdhost_free(RRDHOST *host) {
526
527
freez((void *)host->tags);
528
freez((void *)host->os);
529
+ freez((void *)host->timezone);
530
freez(host->cache_dir);
531
freez(host->varlib_dir);
532
freez(host->rrdpush_send_api_key);
src/rrdpush.c
+11
-4
@@ -294,7 +294,7 @@ static int rrdpush_sender_thread_connect_to_master(RRDHOST *host, int default_po
294
#define HTTP_HEADER_SIZE 8192
295
char http[HTTP_HEADER_SIZE + 1];
296
snprintfz(http, HTTP_HEADER_SIZE,
297
- "STREAM key=%s&hostname=%s®istry_hostname=%s&machine_guid=%s&update_every=%d&os=%s&tags=%s HTTP/1.1\r\n"
297
+ "STREAM key=%s&hostname=%s®istry_hostname=%s&machine_guid=%s&update_every=%d&os=%s&timezone=%s&tags=%s HTTP/1.1\r\n"
298
"User-Agent: netdata-push-service/%s\r\n"
299
"Accept: */*\r\n\r\n"
300
, host->rrdpush_send_api_key
@@ -303,6 +303,7 @@ static int rrdpush_sender_thread_connect_to_master(RRDHOST *host, int default_po
303
, host->machine_guid
304
, default_rrd_update_every
305
, host->os
306
+ , host->timezone
307
, (host->tags)?host->tags:""
308
, program_version
309
);
@@ -634,7 +635,7 @@ static void log_stream_connection(const char *client_ip, const char *client_port
635
log_access("STREAM: %d '[%s]:%s' '%s' host '%s' api key '%s' machine guid '%s'", gettid(), client_ip, client_port, msg, host, api_key, machine_guid);
636
}
637
637
-static int rrdpush_receive(int fd, const char *key, const char *hostname, const char *registry_hostname, const char *machine_guid, const char *os, const char *tags, int update_every, char *client_ip, char *client_port) {
638
+static int rrdpush_receive(int fd, const char *key, const char *hostname, const char *registry_hostname, const char *machine_guid, const char *os, const char *timezone, const char *tags, int update_every, char *client_ip, char *client_port) {
639
RRDHOST *host;
640
int history = default_rrd_history_entries;
641
RRD_MEMORY_MODE mode = default_rrd_memory_mode;
@@ -680,6 +681,7 @@ static int rrdpush_receive(int fd, const char *key, const char *hostname, const
681
, registry_hostname
682
, machine_guid
683
, os
684
+ , timezone
685
, tags
686
, update_every
687
, history
@@ -803,6 +805,7 @@ struct rrdpush_thread {
805
char *registry_hostname;
806
char *machine_guid;
807
char *os;
808
+ char *timezone;
809
char *tags;
810
char *client_ip;
811
char *client_port;
@@ -820,7 +823,7 @@ static void *rrdpush_receiver_thread(void *ptr) {
823
824
825
info("STREAM %s [%s]:%s: receive thread created (task id %d)", rpt->hostname, rpt->client_ip, rpt->client_port, gettid());
823
- rrdpush_receive(rpt->fd, rpt->key, rpt->hostname, rpt->registry_hostname, rpt->machine_guid, rpt->os, rpt->tags, rpt->update_every, rpt->client_ip, rpt->client_port);
826
+ rrdpush_receive(rpt->fd, rpt->key, rpt->hostname, rpt->registry_hostname, rpt->machine_guid, rpt->os, rpt->timezone, rpt->tags, rpt->update_every, rpt->client_ip, rpt->client_port);
827
info("STREAM %s [receive from [%s]:%s]: receive thread ended (task id %d)", rpt->hostname, rpt->client_ip, rpt->client_port, gettid());
828
829
freez(rpt->key);
@@ -828,6 +831,7 @@ static void *rrdpush_receiver_thread(void *ptr) {
831
freez(rpt->registry_hostname);
832
freez(rpt->machine_guid);
833
freez(rpt->os);
834
+ freez(rpt->timezone);
835
freez(rpt->tags);
836
freez(rpt->client_ip);
837
freez(rpt->client_port);
@@ -863,7 +867,7 @@ int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url
867
868
info("STREAM [receive from [%s]:%s]: new client connection.", w->client_ip, w->client_port);
869
866
- char *key = NULL, *hostname = NULL, *registry_hostname = NULL, *machine_guid = NULL, *os = "unknown", *tags = NULL;
870
+ char *key = NULL, *hostname = NULL, *registry_hostname = NULL, *machine_guid = NULL, *os = "unknown", *timezone = "unknown", *tags = NULL;
871
int update_every = default_rrd_update_every;
872
char buf[GUID_LEN + 1];
873
@@ -887,6 +891,8 @@ int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url
891
update_every = (int)strtoul(value, NULL, 0);
892
else if(!strcmp(name, "os"))
893
os = value;
894
+ else if(!strcmp(name, "timezone"))
895
+ timezone = value;
896
else if(!strcmp(name, "tags"))
897
tags = value;
898
else
@@ -968,6 +974,7 @@ int rrdpush_receiver_thread_spawn(RRDHOST *host, struct web_client *w, char *url
974
rpt->registry_hostname = strdupz((registry_hostname && *registry_hostname)?registry_hostname:hostname);
975
rpt->machine_guid = strdupz(machine_guid);
976
rpt->os = strdupz(os);
977
+ rpt->timezone = strdupz(timezone);
978
rpt->tags = (tags)?strdupz(tags):NULL;
979
rpt->client_ip = strdupz(w->client_ip);
980
rpt->client_port = strdupz(w->client_port);