4
4
#include < optional>
5
5
#include < sstream>
6
6
7
+ #include < sys/inotify.h>
8
+ #include < sys/select.h>
9
+
7
10
#include < libsinsp/sinsp.h>
8
11
9
12
#include " CollectionMethod.h"
@@ -279,7 +282,6 @@ void CollectorConfig::InitCollectorConfig(CollectorArgs* args) {
279
282
HandleAfterglowEnvVars ();
280
283
HandleConnectionStatsEnvVars ();
281
284
HandleSinspEnvVars ();
282
- HandleConfig (config_file.value ());
283
285
284
286
host_config_ = ProcessHostHeuristics (*this );
285
287
}
@@ -398,9 +400,11 @@ void CollectorConfig::HandleSinspEnvVars() {
398
400
}
399
401
400
402
void CollectorConfig::YamlConfigToConfig (YAML::Node& yamlConfig) {
403
+ // Don't read the file during a scrape
404
+ std::unique_lock<std::shared_mutex> lock (mutex_);
405
+
401
406
if (yamlConfig.IsNull () || !yamlConfig.IsDefined ()) {
402
- CLOG (FATAL) << " Unable to read config from config file" ;
403
- return ;
407
+ throw std::runtime_error (" Unable to read config from config file" );
404
408
}
405
409
YAML::Node networking = yamlConfig[" networking" ];
406
410
if (!networking) {
@@ -422,33 +426,147 @@ void CollectorConfig::YamlConfigToConfig(YAML::Node& yamlConfig) {
422
426
externalIpsConfig->set_enable (enableExternalIps);
423
427
424
428
SetRuntimeConfig (runtime_config);
425
- CLOG (INFO) << " Runtime configuration:" ;
426
- CLOG (INFO) << GetRuntimeConfigStr ();
429
+ CLOG (INFO) << " Runtime configuration:\n "
430
+ << GetRuntimeConfigStr ();
427
431
428
432
return ;
429
433
}
430
434
431
- void CollectorConfig::HandleConfig (const std::filesystem::path& filePath) {
435
+ bool CollectorConfig::HandleConfig (const std::filesystem::path& filePath) {
432
436
if (!std::filesystem::exists (filePath)) {
433
437
CLOG (DEBUG) << " No configuration file found. " << filePath;
434
- return ;
438
+ return true ;
435
439
}
436
440
437
441
try {
438
442
YAML::Node yamlConfig = YAML::LoadFile (filePath);
439
443
YamlConfigToConfig (yamlConfig);
440
444
} catch (const YAML::BadFile& e) {
441
- CLOG (FATAL ) << " Failed to open the configuration file: " << filePath
442
- << " . Error: " << e. what () ;
445
+ CLOG (ERROR ) << " Failed to open the configuration file: " << filePath << " . Error: " << e. what ();
446
+ return false ;
443
447
} catch (const YAML::ParserException& e) {
444
- CLOG (FATAL ) << " Failed to parse the configuration file: " << filePath
445
- << " . Error: " << e. what () ;
448
+ CLOG (ERROR ) << " Failed to parse the configuration file: " << filePath << " . Error: " << e. what ();
449
+ return false ;
446
450
} catch (const YAML::Exception& e) {
447
- CLOG (FATAL ) << " An error occurred while loading the configuration file: " << filePath
448
- << " . Error: " << e. what () ;
451
+ CLOG (ERROR ) << " An error occurred while loading the configuration file: " << filePath << " . Error: " << e. what ();
452
+ return false ;
449
453
} catch (const std::exception& e) {
450
- CLOG (FATAL) << " An unexpected error occurred while trying to read: " << filePath << e.what ();
454
+ CLOG (ERROR) << " An unexpected error occurred while trying to read: " << filePath << e.what ();
455
+ return false ;
456
+ }
457
+
458
+ return true ;
459
+ }
460
+
461
+ void CollectorConfig::WaitForFileToExist (const std::filesystem::path& filePath) {
462
+ int count = 0 ;
463
+ while (!std::filesystem::exists (filePath) && !thread_.should_stop ()) {
464
+ sleep (1 );
465
+ count++;
466
+ if (count == 45 ) {
467
+ std::unique_lock<std::shared_mutex> lock (mutex_);
468
+ runtime_config_.reset ();
469
+ }
470
+ }
471
+ }
472
+
473
+ int CollectorConfig::WaitForInotifyAddWatch (int fd, const std::filesystem::path& filePath) {
474
+ while (!thread_.should_stop ()) {
475
+ int wd = inotify_add_watch (fd, filePath.c_str (), IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF);
476
+ if (wd < 0 ) {
477
+ CLOG_THROTTLED (ERROR, std::chrono::seconds (30 )) << " Failed to add inotify watch for " << filePath << " : (" << errno << " ) " << StrError ();
478
+ } else {
479
+ return wd;
480
+ }
481
+ sleep (1 );
482
+ }
483
+
484
+ return -1 ;
485
+ }
486
+
487
+ void CollectorConfig::WatchConfigFile (const std::filesystem::path& filePath) {
488
+ fd_set rfds;
489
+ struct timeval tv = {};
490
+ int fd = inotify_init ();
491
+ if (fd < 0 ) {
492
+ CLOG (ERROR) << " inotify_init() failed: " << StrError ();
493
+ CLOG (ERROR) << " Runtime configuration will not be used." ;
494
+ return ;
495
+ }
496
+
497
+ WaitForFileToExist (filePath);
498
+ int wd = WaitForInotifyAddWatch (fd, filePath);
499
+ if (wd == -1 ) {
500
+ CLOG (ERROR) << " Failed to add inotify watch, runtime configuration will not be used." ;
501
+ close (fd);
502
+ return ;
451
503
}
504
+
505
+ bool success = HandleConfig (filePath);
506
+ if (!success) {
507
+ CLOG (FATAL) << " Unable to parse configuration file: " << filePath;
508
+ }
509
+
510
+ char buffer[1024 ];
511
+
512
+ while (!thread_.should_stop ()) {
513
+ tv.tv_sec = 2 ;
514
+ tv.tv_usec = 0 ;
515
+ FD_ZERO (&rfds);
516
+ FD_SET (fd, &rfds);
517
+
518
+ int retval = select (FD_SETSIZE, &rfds, nullptr , nullptr , &tv);
519
+ if (retval < 0 ) {
520
+ CLOG (WARNING) << " 'select' call failed: (" << errno << " ) " << StrError (errno);
521
+ continue ;
522
+ }
523
+
524
+ if (retval == 0 ) {
525
+ // select timed out, check if we should be stopping.
526
+ continue ;
527
+ }
528
+
529
+ // Received event from inotify.
530
+ int length = read (fd, buffer, sizeof (buffer));
531
+ if (length < 0 ) {
532
+ CLOG_THROTTLED (ERROR, std::chrono::seconds (30 )) << " Unable to read event for " << filePath;
533
+ continue ;
534
+ }
535
+
536
+ struct inotify_event * event;
537
+ for (int i = 0 ; i < length; i += sizeof (struct inotify_event ) + event->len ) {
538
+ event = (struct inotify_event *)&buffer[i];
539
+ if (event->mask & IN_MODIFY) {
540
+ HandleConfig (filePath);
541
+ } else if ((event->mask & IN_MOVE_SELF) || (event->mask & IN_DELETE_SELF)) {
542
+ inotify_rm_watch (fd, wd);
543
+
544
+ WaitForFileToExist (filePath);
545
+ wd = WaitForInotifyAddWatch (fd, filePath);
546
+ if (wd == -1 ) {
547
+ // Only situation that could get us here is if collector is
548
+ // stopping, so we break out and let the thread finish.
549
+ break ;
550
+ }
551
+
552
+ HandleConfig (filePath);
553
+ }
554
+ }
555
+ }
556
+
557
+ CLOG (INFO) << " No longer using inotify on " << filePath;
558
+ inotify_rm_watch (fd, wd);
559
+ close (fd);
560
+ }
561
+
562
+ void CollectorConfig::Start () {
563
+ thread_.Start ([this ] { WatchConfigFile (config_file.value ()); });
564
+ CLOG (INFO) << " Watching config file: " << config_file.value ();
565
+ }
566
+
567
+ void CollectorConfig::Stop () {
568
+ thread_.Stop ();
569
+ CLOG (INFO) << " No longer watching config file" << config_file.value ();
452
570
}
453
571
454
572
bool CollectorConfig::TurnOffScrape () const {
0 commit comments