00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "libts.h"
00025 #include "I_Layout.h"
00026
00027 #ifdef HAVE_SYS_PARAM_H
00028 #include <sys/param.h>
00029 #endif
00030
00031 #include "ink_platform.h"
00032 #include "ink_file.h"
00033
00034 #include "Main.h"
00035 #include "List.h"
00036 #include "InkXml.h"
00037
00038 #include "Log.h"
00039 #include "LogField.h"
00040 #include "LogFilter.h"
00041 #include "LogFormat.h"
00042 #include "LogFile.h"
00043 #include "LogBuffer.h"
00044 #include "LogHost.h"
00045 #include "LogObject.h"
00046 #include "LogConfig.h"
00047 #include "LogUtils.h"
00048 #include "SimpleTokenizer.h"
00049
00050 #include "LogCollationAccept.h"
00051 #include "LogPredefined.h"
00052
00053 #define DISK_IS_CONFIG_FULL_MESSAGE \
00054 "Access logging to local log directory suspended - " \
00055 "configured space allocation exhausted."
00056 #define DISK_IS_ACTUAL_FULL_MESSAGE \
00057 "Access logging to local log directory suspended - " \
00058 "no more space on the logging partition."
00059 #define DISK_IS_CONFIG_LOW_MESSAGE \
00060 "Access logging to local log directory suspended - " \
00061 "configured space allocation almost exhausted."
00062 #define DISK_IS_ACTUAL_LOW_MESSAGE \
00063 "Access logging to local log directory suspended - partition space is low."
00064 #define DUP_FORMAT_MESSAGE \
00065 "Format named %s already exists; duplicate format names are not allowed."
00066
00067 #define PARTITION_HEADROOM_MB 10
00068
00069 void
00070 LogConfig::setup_default_values()
00071 {
00072 const unsigned int bufSize = 512;
00073 char name[bufSize];
00074 if (!gethostname(name, bufSize)) {
00075 ink_strlcpy(name, "unknown_host_name", sizeof(name));
00076 }
00077 hostname = ats_strdup(name);
00078
00079 log_buffer_size = (int) (10 * LOG_KILOBYTE);
00080 max_secs_per_buffer = 5;
00081 max_space_mb_for_logs = 100;
00082 max_space_mb_for_orphan_logs = 25;
00083 max_space_mb_headroom = 10;
00084 logfile_perm = 0644;
00085 logfile_dir = ats_strdup(".");
00086
00087 separate_icp_logs = 1;
00088 separate_host_logs = false;
00089
00090 squid_log_enabled = true;
00091 squid_log_is_ascii = true;
00092 squid_log_name = ats_strdup("squid");
00093 squid_log_header = NULL;
00094
00095 common_log_enabled = false;
00096 common_log_is_ascii = true;
00097 common_log_name = ats_strdup("common");
00098 common_log_header = NULL;
00099
00100 extended_log_enabled = false;
00101 extended_log_is_ascii = true;
00102 extended_log_name = ats_strdup("extended");
00103 extended_log_header = NULL;
00104
00105 extended2_log_enabled = false;
00106 extended2_log_is_ascii = true;
00107 extended2_log_name = ats_strdup("extended2");
00108 extended2_log_header = NULL;
00109
00110 collation_mode = Log::NO_COLLATION;
00111 collation_host = ats_strdup("none");
00112 collation_port = 0;
00113 collation_host_tagged = false;
00114 collation_preproc_threads = 1;
00115 collation_secret = ats_strdup("foobar");
00116 collation_retry_sec = 0;
00117 collation_max_send_buffers = 0;
00118
00119 rolling_enabled = Log::NO_ROLLING;
00120 rolling_interval_sec = 86400;
00121 rolling_offset_hr = 0;
00122 rolling_size_mb = 10;
00123 auto_delete_rolled_files = true;
00124 roll_log_files_now = false;
00125
00126 custom_logs_enabled = false;
00127 xml_config_file = ats_strdup("logs_xml.config");
00128 hosts_config_file = ats_strdup("log_hosts.config");
00129
00130
00131
00132 search_log_enabled = false;
00133
00134
00135
00136
00137 search_log_filters = NULL;
00138 search_rolling_interval_sec = 86400;
00139 search_server_ip_addr = 0;
00140 search_server_port = 8080;
00141 search_top_sites = 100;
00142
00143
00144
00145
00146 search_url_filter = NULL;
00147
00148 search_log_file_one = ats_strdup("search_log1");
00149
00150 search_log_file_two = ats_strdup("search_log2");
00151
00152 sampling_frequency = 1;
00153 file_stat_frequency = 16;
00154 space_used_frequency = 900;
00155
00156 use_orphan_log_space_value = false;
00157
00158 ascii_buffer_size = 4 * 9216;
00159 max_line_size = 9216;
00160 }
00161
00162 void *
00163 LogConfig::reconfigure_mgmt_variables(void * , char * ,
00164 int )
00165 {
00166 Note("[TrafficServer:LogConfig] : Roll_Log_Files event received. rolling now");
00167 Log::config->roll_log_files_now = true;
00168 return NULL;
00169 }
00170
00171 void
00172 LogConfig::read_configuration_variables()
00173 {
00174 int val;
00175 char *ptr;
00176
00177 val = (int) REC_ConfigReadInteger("proxy.config.log.log_buffer_size");
00178 if (val > 0) {
00179 log_buffer_size = val;
00180 }
00181
00182 val = (int) REC_ConfigReadInteger("proxy.config.log.max_secs_per_buffer");
00183 if (val > 0) {
00184 max_secs_per_buffer = val;
00185 }
00186
00187 val = (int) REC_ConfigReadInteger("proxy.config.log.max_space_mb_for_logs");
00188 if (val > 0) {
00189 max_space_mb_for_logs = val;
00190 }
00191
00192 val = (int) REC_ConfigReadInteger("proxy.config.log.max_space_mb_for_orphan_logs");
00193 if (val > 0) {
00194 max_space_mb_for_orphan_logs = val;
00195 }
00196
00197 val = (int) REC_ConfigReadInteger("proxy.config.log.max_space_mb_headroom");
00198 if (val > 0) {
00199 max_space_mb_headroom = val;
00200 }
00201
00202
00203 ptr = REC_ConfigReadString("proxy.config.log.logfile_perm");
00204 if (ptr && strlen(ptr) == 9) {
00205 logfile_perm = 0;
00206 char *c = ptr;
00207 if (*c == 'r')
00208 logfile_perm |= S_IRUSR;
00209 c++;
00210 if (*c == 'w')
00211 logfile_perm |= S_IWUSR;
00212 c++;
00213 if (*c == 'x')
00214 logfile_perm |= S_IXUSR;
00215 c++;
00216 if (*c == 'r')
00217 logfile_perm |= S_IRGRP;
00218 c++;
00219 if (*c == 'w')
00220 logfile_perm |= S_IWGRP;
00221 c++;
00222 if (*c == 'x')
00223 logfile_perm |= S_IXGRP;
00224 c++;
00225 if (*c == 'r')
00226 logfile_perm |= S_IROTH;
00227 c++;
00228 if (*c == 'w')
00229 logfile_perm |= S_IWOTH;
00230 c++;
00231 if (*c == 'x')
00232 logfile_perm |= S_IXOTH;
00233 ats_free(ptr);
00234 }
00235
00236 ptr = REC_ConfigReadString("proxy.config.log.hostname");
00237 if (ptr != NULL) {
00238 ats_free(hostname);
00239 hostname = ptr;
00240 }
00241
00242 ats_free(logfile_dir);
00243 logfile_dir = RecConfigReadLogDir();
00244
00245 if (access(logfile_dir, R_OK | W_OK | X_OK) == -1) {
00246
00247 fprintf(stderr,"unable to access log directory '%s': %d, %s\n",
00248 logfile_dir, errno, strerror(errno));
00249 fprintf(stderr,"please set 'proxy.config.log.logfile_dir'\n");
00250 _exit(1);
00251 }
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 val = (int) REC_ConfigReadInteger("proxy.config.log.squid_log_enabled");
00270 squid_log_enabled = (val > 0);
00271
00272 val = (int) REC_ConfigReadInteger("proxy.config.log.squid_log_is_ascii");
00273 squid_log_is_ascii = (val > 0);
00274
00275 ptr = REC_ConfigReadString("proxy.config.log.squid_log_name");
00276 if (ptr != NULL) {
00277 ats_free(squid_log_name);
00278 squid_log_name = ptr;
00279 }
00280
00281 ptr = REC_ConfigReadString("proxy.config.log.squid_log_header");
00282 if (ptr != NULL) {
00283 ats_free(squid_log_header);
00284 squid_log_header = ptr;
00285 }
00286
00287
00288 val = (int) REC_ConfigReadInteger("proxy.config.log.common_log_enabled");
00289 common_log_enabled = (val > 0);
00290
00291 val = (int) REC_ConfigReadInteger("proxy.config.log.common_log_is_ascii");
00292 common_log_is_ascii = (val > 0);
00293
00294 ptr = REC_ConfigReadString("proxy.config.log.common_log_name");
00295 if (ptr != NULL) {
00296 ats_free(common_log_name);
00297 common_log_name = ptr;
00298 }
00299
00300 ptr = REC_ConfigReadString("proxy.config.log.common_log_header");
00301 if (ptr != NULL) {
00302 ats_free(common_log_header);
00303 common_log_header = ptr;
00304 }
00305
00306
00307 val = (int) REC_ConfigReadInteger("proxy.config.log.extended_log_enabled");
00308 extended_log_enabled = (val > 0);
00309
00310 val = (int) REC_ConfigReadInteger("proxy.config.log.extended_log_is_ascii");
00311 extended_log_is_ascii = (val > 0);
00312
00313 ptr = REC_ConfigReadString("proxy.config.log.extended_log_name");
00314 if (ptr != NULL) {
00315 ats_free(extended_log_name);
00316 extended_log_name = ptr;
00317 }
00318
00319 ptr = REC_ConfigReadString("proxy.config.log.extended_log_header");
00320 if (ptr != NULL) {
00321 ats_free(extended_log_header);
00322 extended_log_header = ptr;
00323 }
00324
00325
00326 val = (int) REC_ConfigReadInteger("proxy.config.log.extended2_log_enabled");
00327 extended2_log_enabled = (val > 0);
00328
00329 val = (int) REC_ConfigReadInteger("proxy.config.log.extended2_log_is_ascii");
00330 extended2_log_is_ascii = (val > 0);
00331
00332 ptr = REC_ConfigReadString("proxy.config.log.extended2_log_name");
00333 if (ptr != NULL) {
00334 ats_free(extended2_log_name);
00335 extended2_log_name = ptr;
00336 }
00337
00338 ptr = REC_ConfigReadString("proxy.config.log.extended2_log_header");
00339 if (ptr != NULL) {
00340 ats_free(extended2_log_header);
00341 extended2_log_header = ptr;
00342 }
00343
00344
00345
00346
00347
00348
00349
00350 val = (int) REC_ConfigReadInteger("proxy.config.log.separate_icp_logs");
00351 separate_icp_logs = (val > 0);
00352
00353 val = (int) REC_ConfigReadInteger("proxy.config.log.separate_host_logs");
00354 separate_host_logs = (val > 0);
00355
00356
00357
00358 val = (int) REC_ConfigReadInteger("proxy.local.log.collation_mode");
00359
00360
00361 collation_mode = val;
00362
00363 ptr = REC_ConfigReadString("proxy.config.log.collation_host");
00364 if (ptr != NULL) {
00365 ats_free(collation_host);
00366 collation_host = ptr;
00367 }
00368
00369 val = (int) REC_ConfigReadInteger("proxy.config.log.collation_port");
00370 if (val >= 0) {
00371 collation_port = val;
00372 }
00373
00374 val = (int) REC_ConfigReadInteger("proxy.config.log.collation_host_tagged");
00375 collation_host_tagged = (val > 0);
00376
00377 val = (int) REC_ConfigReadInteger("proxy.config.log.collation_preproc_threads");
00378 if (val > 0 && val <= 128) {
00379 collation_preproc_threads = val;
00380 }
00381
00382 ptr = REC_ConfigReadString("proxy.config.log.collation_secret");
00383 if (ptr != NULL) {
00384 ats_free(collation_secret);
00385 collation_secret = ptr;
00386 }
00387
00388 val = (int) REC_ConfigReadInteger("proxy.config.log.collation_retry_sec");
00389 if (val >= 0) {
00390 collation_retry_sec = val;
00391 }
00392
00393 val = (int) REC_ConfigReadInteger("proxy.config.log.collation_max_send_buffers");
00394 if (val >= 0) {
00395 collation_max_send_buffers = val;
00396 }
00397
00398
00399
00400
00401
00402
00403
00404 rolling_interval_sec = (int) REC_ConfigReadInteger("proxy.config.log.rolling_interval_sec");
00405 rolling_offset_hr = (int) REC_ConfigReadInteger("proxy.config.log.rolling_offset_hr");
00406 rolling_size_mb = (int) REC_ConfigReadInteger("proxy.config.log.rolling_size_mb");
00407
00408 val = (int) REC_ConfigReadInteger("proxy.config.log.rolling_enabled");
00409 if (LogRollingEnabledIsValid(val)) {
00410 rolling_enabled = (Log::RollingEnabledValues)val;
00411 } else {
00412 Warning("invalid value '%d' for '%s', disabling log rolling", val, "proxy.config.log.rolling_enabled");
00413 rolling_enabled = Log::NO_ROLLING;
00414 }
00415
00416 val = (int) REC_ConfigReadInteger("proxy.config.log.auto_delete_rolled_files");
00417 auto_delete_rolled_files = (val > 0);
00418
00419
00420 val = (int) REC_ConfigReadInteger("proxy.config.log.custom_logs_enabled");
00421 custom_logs_enabled = (val > 0);
00422
00423 ptr = REC_ConfigReadString("proxy.config.log.xml_config_file");
00424 if (ptr != NULL) {
00425 ats_free(xml_config_file);
00426 xml_config_file = ptr;
00427 }
00428
00429 ptr = REC_ConfigReadString("proxy.config.log.hosts_config_file");
00430 if (ptr != NULL) {
00431 ats_free(hosts_config_file);
00432 hosts_config_file = ptr;
00433 }
00434
00435
00436 val = (int) REC_ConfigReadInteger("proxy.config.log.sampling_frequency");
00437 if (val > 0) {
00438 sampling_frequency = val;
00439 }
00440
00441 val = (int) REC_ConfigReadInteger("proxy.config.log.file_stat_frequency");
00442 if (val > 0) {
00443 file_stat_frequency = val;
00444 }
00445
00446 val = (int) REC_ConfigReadInteger("proxy.config.log.space_used_frequency");
00447 if (val > 0) {
00448 space_used_frequency = val;
00449 }
00450
00451
00452 val = (int) REC_ConfigReadInteger("proxy.config.log.ascii_buffer_size");
00453 if (val > 0) {
00454 ascii_buffer_size = val;
00455 }
00456
00457 val = (int) REC_ConfigReadInteger("proxy.config.log.max_line_size");
00458 if (val > 0) {
00459 max_line_size = val;
00460 }
00461
00462
00463
00464
00465 val = (int) REC_ConfigReadInteger("proxy.config.log.search_log_enabled");
00466 if (Log::logging_mode == Log::LOG_MODE_FULL)
00467 search_log_enabled = (val > 0);
00468
00469
00470
00471
00472
00473
00474 ptr = REC_ConfigReadString("proxy.config.log.search_log_filters");
00475 if (ptr != NULL) {
00476 search_log_filters = ptr;
00477 }
00478
00479
00480
00481
00482
00483
00484
00485
00486 ptr = REC_ConfigReadString("proxy.config.log.search_url_filter");
00487 if (ptr != NULL) {
00488 search_url_filter = ptr;
00489 }
00490
00491 val = (int) REC_ConfigReadInteger("proxy.config.log.search_top_sites");
00492 if (val > 0) {
00493 search_top_sites = val;
00494 }
00495
00496 ptr = REC_ConfigReadString("proxy.config.log.search_server_ip_addr");
00497 if (ptr != NULL) {
00498 unsigned int ipaddr;
00499 ipaddr = inet_addr(ptr);
00500 if (ipaddr > 0) {
00501 search_server_ip_addr = ipaddr;
00502 } else
00503 search_server_ip_addr = 0;
00504 }
00505
00506 val = (int) REC_ConfigReadInteger("proxy.config.log.search_server_port");
00507 if (val > 0) {
00508 search_server_port = val;
00509 }
00510
00511
00512 val = (int) REC_ConfigReadInteger("proxy.config.log.search_rolling_interval_sec");
00513 if (val > 0) {
00514 search_rolling_interval_sec = val;
00515 }
00516 }
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 LogConfig::LogConfig()
00528 : initialized(false),
00529 reconfiguration_needed(false),
00530 logging_space_exhausted(false), m_space_used(0), m_partition_space_left((int64_t) UINT_MAX),
00531 m_log_collation_accept(NULL),
00532 m_dir_entry(NULL),
00533 m_pDir(NULL),
00534 m_disk_full(false),
00535 m_disk_low(false), m_partition_full(false), m_partition_low(false), m_log_directory_inaccessible(false)
00536 {
00537
00538
00539
00540
00541 setup_default_values();
00542 }
00543
00544
00545
00546
00547
00548
00549
00550 LogConfig::~LogConfig()
00551 {
00552
00553
00554
00555
00556
00557
00558 ats_free(hostname);
00559 ats_free(logfile_dir);
00560 ats_free(squid_log_name);
00561 ats_free(squid_log_header);
00562 ats_free(common_log_name);
00563 ats_free(common_log_header);
00564 ats_free(extended_log_name);
00565 ats_free(extended_log_header);
00566 ats_free(extended2_log_name);
00567 ats_free(extended2_log_header);
00568 ats_free(collation_host);
00569 ats_free(collation_secret);
00570 ats_free(xml_config_file);
00571 ats_free(hosts_config_file);
00572 ats_free(search_log_file_one);
00573 ats_free(search_log_file_two);
00574 ats_free(m_dir_entry);
00575 }
00576
00577
00578
00579
00580
00581
00582 void
00583 LogConfig::setup_collation(LogConfig * prev_config)
00584 {
00585
00586
00587
00588 if (collation_mode < Log::NO_COLLATION || collation_mode >= Log::N_COLLATION_MODES) {
00589 Note("Invalid value %d for proxy.local.log.collation_mode"
00590 " configuration variable (valid range is from %d to %d)\n"
00591 "Log collation disabled", collation_mode, Log::NO_COLLATION, Log::N_COLLATION_MODES - 1);
00592 } else if (collation_mode == Log::NO_COLLATION) {
00593
00594
00595 if (prev_config && prev_config->m_log_collation_accept) {
00596 delete prev_config->m_log_collation_accept;
00597 prev_config->m_log_collation_accept = NULL;
00598 }
00599 } else {
00600 if (!collation_port) {
00601 Note("Cannot activate log collation, %d is an invalid collation port", collation_port);
00602 } else if (collation_mode > Log::COLLATION_HOST && strcmp(collation_host, "none") == 0) {
00603 Note("Cannot activate log collation, \"%s\" is an invalid collation host", collation_host);
00604 } else {
00605 if (collation_mode == Log::COLLATION_HOST) {
00606
00607 ink_assert(m_log_collation_accept == 0);
00608
00609 if (prev_config && prev_config->m_log_collation_accept) {
00610 if (prev_config->collation_port == collation_port) {
00611 m_log_collation_accept = prev_config->m_log_collation_accept;
00612 } else {
00613 delete prev_config->m_log_collation_accept;
00614 }
00615 }
00616
00617 if (!m_log_collation_accept) {
00618 Log::collation_port = collation_port;
00619 m_log_collation_accept = new LogCollationAccept(collation_port);
00620 }
00621 Debug("log", "I am a collation host listening on port %d.", collation_port);
00622 } else {
00623 Debug("log", "I am a collation client (%d)."
00624 " My collation host is %s:%d", collation_mode, collation_host, collation_port);
00625 }
00626
00627 Debug("log", "using iocore log collation");
00628 if (collation_host_tagged) {
00629 LogFormat::turn_tagging_on();
00630 } else {
00631 LogFormat::turn_tagging_off();
00632 }
00633 }
00634 }
00635 }
00636
00637
00638
00639
00640
00641 void
00642 LogConfig::init(LogConfig * prev_config)
00643 {
00644 LogObject * errlog = NULL;
00645
00646 ink_assert(!initialized);
00647
00648 setup_collation(prev_config);
00649
00650 update_space_used();
00651
00652
00653
00654 if (Log::transaction_logging_enabled()) {
00655 setup_log_objects();
00656 }
00657
00658
00659
00660 if (Log::error_logging_enabled()) {
00661 PreDefinedFormatInfo * info;
00662
00663 Debug("log", "creating predefined error log object");
00664 info = MakePredefinedErrorLog(this);
00665 errlog = this->create_predefined_object(info, 0, NULL);
00666 errlog->set_fmt_timestamps();
00667 delete info;
00668 } else {
00669 Log::error_log = NULL;
00670 }
00671
00672 if (prev_config) {
00673
00674 transfer_objects(prev_config);
00675
00676
00677
00678 if (Log::error_log) {
00679 errlog = this->log_object_manager.find_by_format_name(Log::error_log->m_format->name());
00680 }
00681 }
00682
00683 ink_atomic_swap(&Log::error_log, errlog);
00684
00685
00686
00687
00688
00689 size_t num_collation_clients = log_object_manager.get_num_collation_clients();
00690 use_orphan_log_space_value =
00691 (num_collation_clients == 0 ? false :
00692 (log_object_manager.get_num_objects() == num_collation_clients ? true :
00693 max_space_mb_for_orphan_logs > max_space_mb_for_logs));
00694
00695 initialized = true;
00696 }
00697
00698
00699
00700
00701
00702
00703
00704 void
00705 LogConfig::display(FILE * fd)
00706 {
00707 fprintf(fd, "-----------------------------\n");
00708 fprintf(fd, "--- Logging Configuration ---\n");
00709 fprintf(fd, "-----------------------------\n");
00710 fprintf(fd, "Config variables:\n");
00711 fprintf(fd, " log_buffer_size = %d\n", log_buffer_size);
00712 fprintf(fd, " max_secs_per_buffer = %d\n", max_secs_per_buffer);
00713 fprintf(fd, " max_space_mb_for_logs = %d\n", max_space_mb_for_logs);
00714 fprintf(fd, " max_space_mb_for_orphan_logs = %d\n", max_space_mb_for_orphan_logs);
00715 fprintf(fd, " use_orphan_log_space_value = %d\n", use_orphan_log_space_value);
00716 fprintf(fd, " max_space_mb_headroom = %d\n", max_space_mb_headroom);
00717 fprintf(fd, " hostname = %s\n", hostname);
00718 fprintf(fd, " logfile_dir = %s\n", logfile_dir);
00719 fprintf(fd, " logfile_perm = 0%o\n", logfile_perm);
00720 fprintf(fd, " xml_config_file = %s\n", xml_config_file);
00721 fprintf(fd, " hosts_config_file = %s\n", hosts_config_file);
00722 fprintf(fd, " squid_log_enabled = %d\n", squid_log_enabled);
00723 fprintf(fd, " squid_log_is_ascii = %d\n", squid_log_is_ascii);
00724 fprintf(fd, " squid_log_name = %s\n", squid_log_name);
00725 fprintf(fd, " squid_log_header = %s\n", squid_log_header ? squid_log_header : "<no header defined>");
00726 fprintf(fd, " common_log_enabled = %d\n", common_log_enabled);
00727 fprintf(fd, " common_log_is_ascii = %d\n", common_log_is_ascii);
00728 fprintf(fd, " common_log_name = %s\n", common_log_name);
00729 fprintf(fd, " common_log_header = %s\n", common_log_header ? common_log_header : "<no header defined>");
00730 fprintf(fd, " extended_log_enabled = %d\n", extended_log_enabled);
00731 fprintf(fd, " extended_log_is_ascii = %d\n", extended_log_is_ascii);
00732 fprintf(fd, " extended_log_name = %s\n", extended_log_name);
00733 fprintf(fd, " extended_log_header = %s\n", extended_log_header ? extended_log_header : "<no header defined>");
00734 fprintf(fd, " extended2_log_enabled = %d\n", extended2_log_enabled);
00735 fprintf(fd, " extended2_log_is_ascii = %d\n", extended2_log_is_ascii);
00736 fprintf(fd, " extended2_log_name = %s\n", extended2_log_name);
00737 fprintf(fd, " extended2_log_header = %s\n", extended2_log_header ? extended2_log_header : "<no header defined>");
00738 fprintf(fd, " separate_icp_logs = %d\n", separate_icp_logs);
00739 fprintf(fd, " separate_host_logs = %d\n", separate_host_logs);
00740 fprintf(fd, " collation_mode = %d\n", collation_mode);
00741 fprintf(fd, " collation_host = %s\n", collation_host);
00742 fprintf(fd, " collation_port = %d\n", collation_port);
00743 fprintf(fd, " collation_host_tagged = %d\n", collation_host_tagged);
00744 fprintf(fd, " collation_preproc_threads = %d\n", collation_preproc_threads);
00745 fprintf(fd, " collation_secret = %s\n", collation_secret);
00746 fprintf(fd, " rolling_enabled = %d\n", rolling_enabled);
00747 fprintf(fd, " rolling_interval_sec = %d\n", rolling_interval_sec);
00748 fprintf(fd, " rolling_offset_hr = %d\n", rolling_offset_hr);
00749 fprintf(fd, " rolling_size_mb = %d\n", rolling_size_mb);
00750 fprintf(fd, " auto_delete_rolled_files = %d\n", auto_delete_rolled_files);
00751 fprintf(fd, " sampling_frequency = %d\n", sampling_frequency);
00752 fprintf(fd, " file_stat_frequency = %d\n", file_stat_frequency);
00753 fprintf(fd, " space_used_frequency = %d\n", space_used_frequency);
00754
00755 fprintf(fd, "\n");
00756 fprintf(fd, "************ Log Objects (%u objects) ************\n", (unsigned int)log_object_manager.get_num_objects());
00757 log_object_manager.display(fd);
00758
00759 fprintf(fd, "************ Global Filter List (%u filters) ************\n", global_filter_list.count());
00760 global_filter_list.display(fd);
00761
00762 fprintf(fd, "************ Global Format List (%u formats) ************\n", global_format_list.count());
00763 global_format_list.display(fd);
00764 }
00765
00766
00767
00768
00769
00770
00771
00772 void
00773 LogConfig::add_filters_to_search_log_object(const char *format_name)
00774 {
00775 LogObject *obj;
00776
00777 obj = log_object_manager.find_by_format_name(format_name);
00778
00779
00780 SimpleTokenizer tok(search_log_filters, ',');
00781 char *filter_name;
00782 while (filter_name = tok.getNext(), filter_name != 0) {
00783 LogFilter *f;
00784 f = global_filter_list.find_by_name(filter_name);
00785 if (!f) {
00786 Warning("Filter %s not in the global filter list; cannot add to this LogObject", filter_name);
00787 } else {
00788 obj->add_filter(f);
00789 }
00790 }
00791
00792 }
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804 LogObject *
00805 LogConfig::create_predefined_object(const PreDefinedFormatInfo * pdi, size_t num_filters,
00806 LogFilter ** filter, const char *filt_name, bool force_extension)
00807 {
00808 const char *obj_fname;
00809 char obj_filt_fname[PATH_NAME_MAX];
00810
00811 ink_release_assert(pdi != NULL);
00812
00813 if (filt_name) {
00814 ink_string_concatenate_strings_n(obj_filt_fname, PATH_NAME_MAX, pdi->filename, "-", filt_name, NULL);
00815 obj_fname = obj_filt_fname;
00816 } else {
00817 obj_fname = pdi->filename;
00818 }
00819
00820 if (force_extension) {
00821 switch (pdi->filefmt) {
00822 case LOG_FILE_ASCII:
00823 ink_string_append(obj_filt_fname, (char *)LOG_FILE_ASCII_OBJECT_FILENAME_EXTENSION, PATH_NAME_MAX);
00824 break;
00825 case LOG_FILE_BINARY:
00826 ink_string_append(obj_filt_fname, (char *)LOG_FILE_BINARY_OBJECT_FILENAME_EXTENSION, PATH_NAME_MAX);
00827 break;
00828 default:
00829 break;
00830 }
00831 }
00832
00833
00834
00835 LogObject *obj;
00836 obj = new LogObject(pdi->format, logfile_dir, obj_fname,
00837 pdi->filefmt, pdi->header, (Log::RollingEnabledValues)rolling_enabled,
00838 collation_preproc_threads, rolling_interval_sec,
00839 rolling_offset_hr, rolling_size_mb);
00840
00841 if (pdi->collatable) {
00842 if (collation_mode == Log::SEND_STD_FMTS || collation_mode == Log::SEND_STD_AND_NON_XML_CUSTOM_FMTS) {
00843
00844 LogHost *loghost = new LogHost(obj->get_full_filename(), obj->get_signature());
00845 ink_assert(loghost != NULL);
00846
00847 loghost->set_name_port(collation_host, collation_port);
00848 obj->add_loghost(loghost, false);
00849 }
00850 }
00851
00852 for (size_t i = 0; i < num_filters; ++i) {
00853 obj->add_filter(filter[i]);
00854 }
00855
00856
00857 if (log_object_manager.manage_object(obj) != LogObjectManager::NO_FILENAME_CONFLICTS) {
00858 delete obj;
00859 return NULL;
00860 }
00861
00862 return obj;
00863 }
00864
00865 void
00866 LogConfig::create_predefined_objects_with_filter(const PreDefinedFormatList & predef, size_t nfilters,
00867 LogFilter ** filters, const char * filt_name, bool force_extension)
00868 {
00869 PreDefinedFormatInfo *pdi;
00870
00871 for (pdi = predef.formats.head; pdi != NULL; pdi = (pdi->link).next) {
00872 this->create_predefined_object(pdi, nfilters, filters, filt_name, force_extension);
00873 }
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890 LogFilter *
00891 LogConfig::split_by_protocol(const PreDefinedFormatList & predef)
00892 {
00893 if (!separate_icp_logs) {
00894 return NULL;
00895 }
00896
00897 enum { icp=0,
00898 http
00899 };
00900
00901 int64_t value[] = { LOG_ENTRY_ICP,
00902 LOG_ENTRY_HTTP
00903 };
00904 const char *name[] = { "icp", "http" };
00905 const char *filter_name[] = { "__icp__", "__http__" };
00906 int64_t filter_val[http];
00907 size_t n = 0;
00908
00909 LogField *etype_field = Log::global_field_list.find_by_symbol("etype");
00910 ink_assert(etype_field);
00911
00912 if (separate_icp_logs) {
00913 if (separate_icp_logs == 1) {
00914 LogFilter * filter[1];
00915
00916 filter[0] = new LogFilterInt(filter_name[icp], etype_field, LogFilter::ACCEPT, LogFilter::MATCH, value[icp]);
00917 create_predefined_objects_with_filter(predef, countof(filter), filter, name[icp]);
00918 delete filter[0];
00919 }
00920 filter_val[n++] = value[icp];
00921 }
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931 if (n > 0) {
00932 return new LogFilterInt("__reject_protocols__", etype_field, LogFilter::REJECT, LogFilter::MATCH, n, filter_val);
00933 }
00934 return NULL;
00935 }
00936
00937 size_t
00938 LogConfig::split_by_hostname(const PreDefinedFormatList & predef, LogFilter * reject_protocol_filter)
00939 {
00940 size_t n_hosts;
00941 char **host = read_log_hosts_file(&n_hosts);
00942
00943 if (n_hosts) {
00944
00945 size_t num_filt = 0;
00946 LogFilter *rp_ah[2];
00947 LogField *shn_field = Log::global_field_list.find_by_symbol("shn");
00948 ink_assert(shn_field);
00949
00950 if (reject_protocol_filter) {
00951 rp_ah[num_filt++] = reject_protocol_filter;
00952 }
00953
00954 for (size_t i = 0; i < n_hosts; ++i) {
00955
00956
00957
00958 char filter_name[LOG_MAX_FORMAT_LINE + 12];
00959 snprintf(filter_name, LOG_MAX_FORMAT_LINE, "__accept_%s__", host[i]);
00960 rp_ah[num_filt] = new LogFilterString(filter_name, shn_field, LogFilter::ACCEPT,
00961 LogFilter::CASE_INSENSITIVE_CONTAIN, host[i]);
00962
00963 create_predefined_objects_with_filter(predef, num_filt + 1, rp_ah, host[i], true);
00964 delete rp_ah[num_filt];
00965 }
00966
00967 LogFilter *rp_rh[2];
00968
00969 num_filt = 0;
00970
00971 if (reject_protocol_filter) {
00972 rp_rh[num_filt++] = reject_protocol_filter;
00973 }
00974
00975 rp_rh[num_filt] = new LogFilterString("__reject_hosts__", shn_field, LogFilter::REJECT,
00976 LogFilter::CASE_INSENSITIVE_CONTAIN, n_hosts, host);
00977
00978
00979
00980
00981
00982 create_predefined_objects_with_filter(predef, num_filt + 1, rp_rh);
00983 delete rp_rh[num_filt];
00984
00985 delete[]host;
00986
00987 }
00988
00989
00990 return n_hosts;
00991 }
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010 void
01011 LogConfig::setup_log_objects()
01012 {
01013 Debug("log", "creating objects...");
01014
01015
01016
01017
01018
01019
01020 PreDefinedFormatList predef;
01021
01022 predef.init(this);
01023
01024
01025
01026 LogFilter *reject_protocol_filter = split_by_protocol(predef);
01027
01028
01029
01030 size_t num_hosts = 0;
01031 if (separate_host_logs) {
01032 num_hosts = split_by_hostname(predef, reject_protocol_filter);
01033 }
01034
01035 if (num_hosts == 0) {
01036
01037
01038
01039
01040
01041 LogFilter *f[1];
01042 f[0] = reject_protocol_filter;
01043 create_predefined_objects_with_filter(predef, countof(f), f);
01044 }
01045
01046 delete reject_protocol_filter;
01047
01048
01049
01050
01051 global_filter_list.clear();
01052
01053
01054
01055
01056
01057
01058
01059
01060 if (search_log_enabled) {
01061 Debug("log", "creating search log object");
01062
01063 read_xml_log_config(1);
01064 }
01065
01066 if (custom_logs_enabled) {
01067
01068 read_xml_log_config(0);
01069 }
01070
01071
01072
01073
01074 if (search_log_enabled) {
01075 if (search_log_filters) {
01076 add_filters_to_search_log_object("m_search_one");
01077 add_filters_to_search_log_object("m_search_two");
01078 }
01079 }
01080
01081
01082 log_object_manager.open_local_pipes();
01083
01084 if (is_debug_tag_set("log")) {
01085 log_object_manager.display();
01086 }
01087 }
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099 int
01100 LogConfig::reconfigure(const char * , RecDataT ,
01101 RecData , void * )
01102 {
01103 Debug("log-config", "Reconfiguration request accepted");
01104 Log::config->reconfiguration_needed = true;
01105 return 0;
01106 }
01107
01108
01109
01110
01111
01112
01113
01114
01115 void
01116 LogConfig::register_config_callbacks()
01117 {
01118 static const char * names[] = {
01119 "proxy.config.log.log_buffer_size",
01120 "proxy.config.log.max_secs_per_buffer",
01121 "proxy.config.log.max_space_mb_for_logs",
01122 "proxy.config.log.max_space_mb_for_orphan_logs",
01123 "proxy.config.log.max_space_mb_headroom",
01124 "proxy.config.log.logfile_perm",
01125 "proxy.config.log.hostname",
01126 "proxy.config.log.logfile_dir",
01127 "proxy.config.log.squid_log_enabled",
01128 "proxy.config.log.squid_log_is_ascii",
01129 "proxy.config.log.squid_log_name",
01130 "proxy.config.log.squid_log_header",
01131 "proxy.config.log.common_log_enabled",
01132 "proxy.config.log.common_log_is_ascii",
01133 "proxy.config.log.common_log_name",
01134 "proxy.config.log.common_log_header",
01135 "proxy.config.log.extended_log_enabled",
01136 "proxy.config.log.extended_log_is_ascii",
01137 "proxy.config.log.extended_log_name",
01138 "proxy.config.log.extended_log_header",
01139 "proxy.config.log.extended2_log_enabled",
01140 "proxy.config.log.extended2_log_is_ascii",
01141 "proxy.config.log.extended2_log_name",
01142 "proxy.config.log.extended2_log_header",
01143 "proxy.config.log.separate_icp_logs",
01144 "proxy.config.log.separate_host_logs",
01145 "proxy.local.log.collation_mode",
01146 "proxy.config.log.collation_host",
01147 "proxy.config.log.collation_port",
01148 "proxy.config.log.collation_host_tagged",
01149 "proxy.config.log.collation_secret",
01150 "proxy.config.log.collation_retry_sec",
01151 "proxy.config.log.collation_max_send_buffers",
01152 "proxy.config.log.rolling_enabled",
01153 "proxy.config.log.rolling_interval_sec",
01154 "proxy.config.log.rolling_offset_hr",
01155 "proxy.config.log.rolling_size_mb",
01156 "proxy.config.log.auto_delete_rolled_files",
01157 "proxy.config.log.custom_logs_enabled",
01158 "proxy.config.log.xml_config_file",
01159 "proxy.config.log.hosts_config_file",
01160 "proxy.config.log.sampling_frequency",
01161 "proxy.config.log.file_stat_frequency",
01162 "proxy.config.log.space_used_frequency",
01163 "proxy.config.log.search_rolling_interval_sec",
01164 "proxy.config.log.search_log_enabled",
01165 "proxy.config.log.search_top_sites",
01166 "proxy.config.log.search_server_ip_addr",
01167 "proxy.config.log.search_server_port",
01168 "proxy.config.log.search_url_filter",
01169 };
01170
01171
01172 for (unsigned i = 0; i < countof(names); ++i) {
01173 REC_RegisterConfigUpdateFunc(names[i], &LogConfig::reconfigure, NULL);
01174 }
01175 }
01176
01177
01178
01179
01180
01181
01182
01183
01184 void
01185 LogConfig::register_stat_callbacks()
01186 {
01187
01188
01189
01190 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01191 "proxy.process.log.event_log_error_ok",
01192 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_event_log_error_ok_stat, RecRawStatSyncCount);
01193 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01194 "proxy.process.log.event_log_error_skip",
01195 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_event_log_error_skip_stat, RecRawStatSyncCount);
01196 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01197 "proxy.process.log.event_log_error_aggr",
01198 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_event_log_error_aggr_stat, RecRawStatSyncCount);
01199 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01200 "proxy.process.log.event_log_error_full",
01201 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_event_log_error_full_stat, RecRawStatSyncCount);
01202 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01203 "proxy.process.log.event_log_error_fail",
01204 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_event_log_error_fail_stat, RecRawStatSyncCount);
01205 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01206 "proxy.process.log.event_log_access_ok",
01207 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_event_log_access_ok_stat, RecRawStatSyncCount);
01208 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01209 "proxy.process.log.event_log_access_skip",
01210 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_event_log_access_skip_stat, RecRawStatSyncCount);
01211 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01212 "proxy.process.log.event_log_access_aggr",
01213 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_event_log_access_aggr_stat, RecRawStatSyncCount);
01214 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01215 "proxy.process.log.event_log_access_full",
01216 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_event_log_access_full_stat, RecRawStatSyncCount);
01217 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01218 "proxy.process.log.event_log_access_fail",
01219 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_event_log_access_fail_stat, RecRawStatSyncCount);
01220
01221
01222
01223 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01224 "proxy.process.log.num_sent_to_network",
01225 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_num_sent_to_network_stat, RecRawStatSyncSum);
01226 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01227 "proxy.process.log.num_lost_before_sent_to_network",
01228 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_num_lost_before_sent_to_network_stat, RecRawStatSyncSum);
01229 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01230 "proxy.process.log.num_received_from_network",
01231 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_num_received_from_network_stat, RecRawStatSyncSum);
01232 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01233 "proxy.process.log.num_flush_to_disk",
01234 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_num_flush_to_disk_stat, RecRawStatSyncSum);
01235 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01236 "proxy.process.log.num_lost_before_flush_to_disk",
01237 RECD_COUNTER, RECP_PERSISTENT, (int) log_stat_num_lost_before_flush_to_disk_stat, RecRawStatSyncSum);
01238 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01239 "proxy.process.log.bytes_lost_before_preproc",
01240 RECD_INT, RECP_PERSISTENT, (int) log_stat_bytes_lost_before_preproc_stat, RecRawStatSyncSum);
01241 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01242 "proxy.process.log.bytes_sent_to_network",
01243 RECD_INT, RECP_PERSISTENT, (int) log_stat_bytes_sent_to_network_stat, RecRawStatSyncSum);
01244 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01245 "proxy.process.log.bytes_lost_before_sent_to_network",
01246 RECD_INT, RECP_PERSISTENT, (int) log_stat_bytes_lost_before_sent_to_network_stat, RecRawStatSyncSum);
01247 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01248 "proxy.process.log.bytes_received_from_network",
01249 RECD_INT, RECP_PERSISTENT, (int) log_stat_bytes_received_from_network_stat, RecRawStatSyncSum);
01250 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01251 "proxy.process.log.bytes_flush_to_disk",
01252 RECD_INT, RECP_PERSISTENT, (int) log_stat_bytes_flush_to_disk_stat, RecRawStatSyncSum);
01253 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01254 "proxy.process.log.bytes_lost_before_flush_to_disk",
01255 RECD_INT, RECP_PERSISTENT, (int) log_stat_bytes_lost_before_flush_to_disk_stat, RecRawStatSyncSum);
01256 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01257 "proxy.process.log.bytes_written_to_disk",
01258 RECD_INT, RECP_PERSISTENT, (int) log_stat_bytes_written_to_disk_stat, RecRawStatSyncSum);
01259 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01260 "proxy.process.log.bytes_lost_before_written_to_disk",
01261 RECD_INT, RECP_PERSISTENT, (int) log_stat_bytes_lost_before_written_to_disk_stat, RecRawStatSyncSum);
01262
01263
01264
01265 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01266 "proxy.process.log.log_files_open",
01267 RECD_COUNTER, RECP_NON_PERSISTENT, (int) log_stat_log_files_open_stat, RecRawStatSyncSum);
01268 RecRegisterRawStat(log_rsb, RECT_PROCESS,
01269 "proxy.process.log.log_files_space_used",
01270 RECD_INT, RECP_NON_PERSISTENT, (int) log_stat_log_files_space_used_stat, RecRawStatSyncSum);
01271 }
01272
01273
01274
01275
01276
01277
01278
01279
01280 void
01281 LogConfig::register_mgmt_callbacks()
01282 {
01283 RecRegisterManagerCb(REC_EVENT_ROLL_LOG_FILES, &LogConfig::reconfigure_mgmt_variables, NULL);
01284 }
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294 bool LogConfig::space_to_write(int64_t bytes_to_write)
01295 {
01296 int64_t config_space, partition_headroom;
01297 int64_t logical_space_used, physical_space_left;
01298 bool space;
01299
01300 config_space = (int64_t) get_max_space_mb() * LOG_MEGABYTE;
01301 partition_headroom = (int64_t) PARTITION_HEADROOM_MB * LOG_MEGABYTE;
01302
01303 logical_space_used = m_space_used + bytes_to_write;
01304 physical_space_left = m_partition_space_left - (int64_t) bytes_to_write;
01305
01306 space = ((logical_space_used<config_space) && (physical_space_left> partition_headroom));
01307
01308 Debug("logspace", "logical space used %" PRId64 ", configured space %" PRId64
01309 ", physical space left %" PRId64 ", partition headroom %" PRId64 ", space %s available",
01310 logical_space_used, config_space, physical_space_left, partition_headroom,
01311 space ? "is" : "is not");
01312
01313 return space;
01314 }
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330 static int
01331 delete_candidate_compare(const LogDeleteCandidate * a, const LogDeleteCandidate * b)
01332 {
01333 return ((int) (a->mtime - b->mtime));
01334 }
01335
01336 void
01337 LogConfig::update_space_used()
01338 {
01339
01340
01341 if (m_log_directory_inaccessible)
01342 return;
01343
01344 static const int MAX_CANDIDATES = 128;
01345 LogDeleteCandidate candidates[MAX_CANDIDATES];
01346 int i, victim, candidate_count;
01347 int64_t total_space_used, partition_space_left;
01348 char path[MAXPATHLEN];
01349 int sret;
01350 struct dirent *result;
01351 struct stat sbuf;
01352 DIR *ld;
01353
01354
01355
01356 if (!logfile_dir) {
01357 const char *msg = "Logging directory not specified";
01358 Error("%s", msg);
01359 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, "%s", msg);
01360 m_log_directory_inaccessible = true;
01361 return;
01362 }
01363
01364
01365 int err;
01366 do {
01367 err = access(logfile_dir, R_OK | W_OK | X_OK);
01368 } while ((err < 0) && (errno == EINTR));
01369
01370 if (err < 0) {
01371 const char *msg = "Error accessing logging directory %s: %s.";
01372 Error(msg, logfile_dir, strerror(errno));
01373 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, msg, logfile_dir, strerror(errno));
01374 m_log_directory_inaccessible = true;
01375 return;
01376 }
01377
01378 ld =::opendir(logfile_dir);
01379 if (ld == NULL) {
01380 const char *msg = "Error opening logging directory %s to perform a space check: %s.";
01381 Error(msg, logfile_dir, strerror(errno));
01382 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, msg, logfile_dir, strerror(errno));
01383 m_log_directory_inaccessible = true;
01384 return;
01385 }
01386
01387 if (!m_dir_entry) {
01388 long name_max = pathconf(logfile_dir, _PC_NAME_MAX);
01389
01390
01391
01392 ink_release_assert(name_max > 0);
01393
01394 m_dir_entry = (struct dirent *)ats_malloc(sizeof(struct dirent) + name_max + 1);
01395 }
01396
01397 total_space_used = 0LL;
01398
01399 candidate_count = 0;
01400
01401 while (readdir_r(ld, m_dir_entry, &result) == 0) {
01402
01403 if (!result) {
01404 break;
01405 }
01406
01407 snprintf(path, MAXPATHLEN, "%s/%s", logfile_dir, m_dir_entry->d_name);
01408
01409 sret =::stat(path, &sbuf);
01410 if (sret != -1 && S_ISREG(sbuf.st_mode)) {
01411
01412 total_space_used += (int64_t) sbuf.st_size;
01413
01414 if (auto_delete_rolled_files && LogFile::rolled_logfile(m_dir_entry->d_name) && candidate_count < MAX_CANDIDATES) {
01415
01416
01417
01418 candidates[candidate_count].name = ats_strdup(path);
01419 candidates[candidate_count].size = (int64_t) sbuf.st_size;
01420 candidates[candidate_count].mtime = sbuf.st_mtime;
01421 candidate_count++;
01422 }
01423 }
01424 }
01425 ::closedir(ld);
01426
01427
01428
01429
01430 partition_space_left = m_partition_space_left;
01431
01432 struct statvfs fs;
01433
01434 if (::statvfs(logfile_dir, &fs) >= 0) {
01435 partition_space_left = (int64_t) fs.f_bavail * (int64_t) fs.f_bsize;
01436 }
01437
01438
01439
01440
01441 m_space_used = total_space_used;
01442 m_partition_space_left = partition_space_left;
01443 RecSetRawStatSum(log_rsb, log_stat_log_files_space_used_stat, m_space_used);
01444 RecSetRawStatCount(log_rsb, log_stat_log_files_space_used_stat, 1);
01445
01446 Debug("logspace", "%" PRId64 " bytes being used for logs", m_space_used);
01447 Debug("logspace", "%" PRId64 " bytes left on partition", m_partition_space_left);
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460 int64_t max_space = (int64_t) get_max_space_mb() * LOG_MEGABYTE;
01461 int64_t headroom = (int64_t) max_space_mb_headroom * LOG_MEGABYTE;
01462
01463 if (candidate_count > 0 && !space_to_write(headroom)) {
01464
01465 Debug("logspace", "headroom reached, trying to clear space ...");
01466 Debug("logspace", "sorting %d delete candidates ...", candidate_count);
01467 qsort(candidates, candidate_count, sizeof(LogDeleteCandidate),
01468 (int (*)(const void *, const void *)) delete_candidate_compare);
01469
01470 for (victim = 0; victim < candidate_count; victim++) {
01471
01472 if (space_to_write(headroom + log_buffer_size)) {
01473 Debug("logspace", "low water mark reached; stop deleting");
01474 break;
01475 }
01476
01477 Debug("logspace", "auto-deleting %s", candidates[victim].name);
01478
01479 if (unlink(candidates[victim].name) < 0) {
01480 Note("Traffic Server was Unable to auto-delete rolled "
01481 "logfile %s: %s.", candidates[victim].name, strerror(errno));
01482 } else {
01483 Debug("logspace", "The rolled logfile, %s, was auto-deleted; "
01484 "%" PRId64 " bytes were reclaimed.", candidates[victim].name, candidates[victim].size);
01485 m_space_used -= candidates[victim].size;
01486 m_partition_space_left += candidates[victim].size;
01487 }
01488 }
01489 }
01490
01491
01492
01493 for (i = 0; i < candidate_count; i++) {
01494 ats_free(candidates[i].name);
01495 }
01496
01497
01498
01499
01500
01501
01502
01503 if (!space_to_write(headroom)) {
01504 if (!logging_space_exhausted)
01505 Note("Logging space exhausted, any logs writing to local disk will be dropped!");
01506
01507 logging_space_exhausted = true;
01508
01509
01510
01511
01512
01513
01514 if (m_space_used >= max_space) {
01515 if (!m_disk_full) {
01516 m_disk_full = true;
01517 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, DISK_IS_CONFIG_FULL_MESSAGE);
01518 Warning(DISK_IS_CONFIG_FULL_MESSAGE);
01519 }
01520 }
01521
01522
01523
01524 else if (m_partition_space_left <= 0) {
01525 if (!m_partition_full) {
01526 m_partition_full = true;
01527 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, DISK_IS_ACTUAL_FULL_MESSAGE);
01528 Warning(DISK_IS_ACTUAL_FULL_MESSAGE);
01529 }
01530 }
01531
01532
01533
01534 else if (m_space_used + headroom >= max_space) {
01535 if (!m_disk_low) {
01536 m_disk_low = true;
01537 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, DISK_IS_CONFIG_LOW_MESSAGE);
01538 Warning(DISK_IS_CONFIG_LOW_MESSAGE);
01539 }
01540 } else {
01541 if (!m_partition_low) {
01542 m_partition_low = true;
01543 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, DISK_IS_ACTUAL_LOW_MESSAGE);
01544 Warning(DISK_IS_ACTUAL_LOW_MESSAGE);
01545 }
01546 }
01547 } else {
01548
01549
01550
01551 if (logging_space_exhausted)
01552 Note("Logging space is no longer exhausted.");
01553
01554 logging_space_exhausted = false;
01555 if (m_disk_full || m_partition_full) {
01556 Note("Logging disk is no longer full; access logging to local log directory resumed.");
01557 m_disk_full = false;
01558 m_partition_full = false;
01559 }
01560 if (m_disk_low || m_partition_low) {
01561 Note("Logging disk is no longer low; access logging to local log directory resumed.");
01562 m_disk_low = false;
01563 m_partition_low = false;
01564 }
01565 }
01566 }
01567
01568
01569
01570
01571
01572
01573
01574
01575 static char xml_config_buffer[] = "<LogFilter> \
01576 <Name = \"reject_gif\"/> \
01577 <Action = \"REJECT\"/> \
01578 <Condition = \"cqup CASE_INSENSITIVE_CONTAIN .gif\"/> \
01579 </LogFilter>\
01580 \
01581 <LogFilter> \
01582 <Name = \"reject_jpg\"/> \
01583 <Action = \"REJECT\"/> \
01584 <Condition = \"cqup CASE_INSENSITIVE_CONTAIN .jpg\"/> \
01585 </LogFilter>\
01586 \
01587 <LogFilter> \
01588 <Name = \"only_cache_miss\"/> \
01589 <Action = \"ACCEPT\"/> \
01590 <Condition = \"crc MATCH TCP_MISS\"/> \
01591 </LogFilter> \
01592 \
01593 <LogFormat> \
01594 <Name = \"m_search_one\"/> \
01595 <Format = \"%%<cquc> %%<cqtt>\"/> \
01596 </LogFormat> \
01597 \
01598 <LogFormat> \
01599 <Name = \"m_search_two\"/> \
01600 <Format = \"%%<cquc> %%<crc>\"/> \
01601 </LogFormat> \
01602 \
01603 <LogObject> \
01604 <Filename = \"search_log1\"/> \
01605 <Format = \"m_search_one\"/> \
01606 <Filters = \"reject_gif\", \"reject_jpg\"/> \
01607 <RollingIntervalSec = \"%d\"/> \
01608 </LogObject> \
01609 \
01610 <LogObject> \
01611 <Filename = \"search_log2\"/> \
01612 <Format = \"m_search_two\"/> \
01613 <Filters = \"reject_gif\", \"reject_jpg\", \"only_cache_miss\"/> \
01614 <RollingIntervalSec = \"%d\"/> \
01615 </LogObject>";
01616 void
01617 LogConfig::read_xml_log_config(int from_memory)
01618 {
01619 ats_scoped_str config_path;
01620
01621 if (!from_memory) {
01622 if (xml_config_file == NULL) {
01623 Note("No log config file to read");
01624 return;
01625 }
01626
01627 config_path = Layout::get()->relative_to(Layout::get()->sysconfdir, xml_config_file);
01628 }
01629
01630 InkXmlConfigFile log_config(config_path ? (const char *)config_path : "memory://builtin");
01631
01632 if (!from_memory) {
01633 Debug("log-config", "Reading log config file %s", (const char *)config_path);
01634 Debug("xml", "%s is an XML-based config file", (const char *)config_path);
01635
01636 if (log_config.parse() < 0) {
01637 Note("Error parsing log config file %s; ensure that it is XML-based", (const char *)config_path);
01638 return;
01639 }
01640
01641 if (is_debug_tag_set("xml")) {
01642 log_config.display();
01643 }
01644 } else {
01645 int filedes[2];
01646 int nbytes = sizeof(xml_config_buffer);
01647 const size_t ptr_size = nbytes + 20;
01648 char *ptr = (char *)ats_malloc(ptr_size);
01649
01650 if (pipe(filedes) != 0) {
01651 Note("xml parsing: Error in Opening a pipe");
01652 ats_free(ptr);
01653 return;
01654 }
01655
01656 snprintf(ptr, ptr_size, xml_config_buffer, search_rolling_interval_sec, search_rolling_interval_sec);
01657 nbytes = strlen(ptr);
01658 if (write(filedes[1], ptr, nbytes) != nbytes) {
01659 Note("Error in writing to pipe.");
01660 ats_free(ptr);
01661 close(filedes[1]);
01662 close(filedes[0]);
01663 return;
01664 }
01665 ats_free(ptr);
01666 close(filedes[1]);
01667
01668 if (log_config.parse(filedes[0]) < 0) {
01669 Note("Error parsing log config info from memory.");
01670 return;
01671 }
01672 }
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685 InkXmlObject *xobj;
01686 InkXmlAttr *xattr;
01687
01688 for (xobj = log_config.first(); xobj; xobj = log_config.next(xobj)) {
01689
01690 Debug("xml", "XmlObject: %s", xobj->object_name());
01691
01692 if (strcmp(xobj->object_name(), "LogFormat") == 0) {
01693
01694
01695
01696
01697
01698 NameList name;
01699 NameList format;
01700 NameList interval;
01701
01702 for (xattr = xobj->first(); xattr; xattr = xobj->next(xattr)) {
01703 Debug("xml", "XmlAttr : <%s,%s>", xattr->tag(), xattr->value());
01704
01705 if (strcasecmp(xattr->tag(), "Name") == 0) {
01706 name.enqueue(xattr->value());
01707 } else if (strcasecmp(xattr->tag(), "Format") == 0) {
01708 format.enqueue(xattr->value());
01709 } else if (strcasecmp(xattr->tag(), "Interval") == 0) {
01710 interval.enqueue(xattr->value());
01711 } else {
01712 Note("Unknown attribute %s for %s; ignoring", xattr->tag(), xobj->object_name());
01713 }
01714 }
01715
01716
01717
01718 if (name.count() == 0) {
01719 Note("'Name' attribute missing for LogFormat object");
01720 continue;
01721 }
01722 if (format.count() == 0) {
01723 Note("'Format' attribute missing for LogFormat object");
01724 continue;
01725 }
01726 if (name.count() > 1) {
01727 Note("Multiple values for 'Name' attribute in %s; using the first one", xobj->object_name());
01728 }
01729 if (format.count() > 1) {
01730 Note("Multiple values for 'Format' attribute in %s; using the first one", xobj->object_name());
01731 }
01732
01733 char *format_str = format.dequeue();
01734 char *name_str = name.dequeue();
01735 unsigned interval_num = 0;
01736
01737
01738
01739
01740 if (LogField::fieldlist_contains_aggregates(format_str)) {
01741 if (interval.count() == 0) {
01742 Note("'Interval' attribute missing for LogFormat object"
01743 " %s that contains aggregate operators: %s", name_str, format_str);
01744 continue;
01745 } else if (interval.count() > 1) {
01746 Note("Multiple values for 'Interval' attribute in %s; using the first one", xobj->object_name());
01747 }
01748
01749
01750 interval_num = ink_atoui(interval.dequeue());
01751 } else if (interval.count() > 0) {
01752 Note("Format %s has no aggregates, ignoring 'Interval' attribute.", name_str);
01753 }
01754
01755
01756 LogFormat *fmt = new LogFormat(name_str, format_str, interval_num);
01757
01758 ink_assert(fmt != NULL);
01759 if (fmt->valid()) {
01760 global_format_list.add(fmt, false);
01761
01762 if (is_debug_tag_set("xml")) {
01763 printf("The following format was added to the global format list\n");
01764 fmt->displayAsXML(stdout);
01765 }
01766 } else {
01767 Note("Format named \"%s\" will not be active; not a valid format", fmt->name()? fmt->name() : "");
01768 delete fmt;
01769 }
01770 }
01771
01772 else if (strcmp(xobj->object_name(), "LogFilter") == 0) {
01773 int i;
01774
01775
01776
01777
01778 NameList name;
01779 NameList condition;
01780 NameList action;
01781
01782 for (xattr = xobj->first(); xattr; xattr = xobj->next(xattr)) {
01783 Debug("xml", "XmlAttr : <%s,%s>", xattr->tag(), xattr->value());
01784
01785 if (strcasecmp(xattr->tag(), "Name") == 0) {
01786 name.enqueue(xattr->value());
01787 } else if (strcasecmp(xattr->tag(), "Action") == 0) {
01788 action.enqueue(xattr->value());
01789 } else if (strcasecmp(xattr->tag(), "Condition") == 0) {
01790 condition.enqueue(xattr->value());
01791 } else {
01792 Note("Unknown attribute %s for %s; ignoring", xattr->tag(), xobj->object_name());
01793 }
01794 }
01795
01796
01797
01798 if (name.count() == 0) {
01799 Note("'Name' attribute missing for LogFilter object");
01800 continue;
01801 }
01802 if (action.count() == 0) {
01803 Note("'Action' attribute missing for LogFilter object");
01804 continue;
01805 }
01806 if (condition.count() == 0) {
01807 Note("'Condition' attribute missing for LogFilter object");
01808 continue;
01809 }
01810 if (name.count() > 1) {
01811 Note("Multiple values for 'Name' attribute in %s; using the first one", xobj->object_name());
01812 }
01813 if (action.count() > 1) {
01814 Note("Multiple values for 'Action' attribute in %s; using the first one", xobj->object_name());
01815 }
01816 if (condition.count() > 1) {
01817 Note("Multiple values for 'Condition' attribute in %s; using the first one", xobj->object_name());
01818 }
01819
01820 char *filter_name = name.dequeue();
01821
01822
01823
01824 char *action_str = action.dequeue();
01825 LogFilter::Action act = LogFilter::REJECT;
01826 for (i = 0; i < LogFilter::N_ACTIONS; i++) {
01827 if (strcasecmp(action_str, LogFilter::ACTION_NAME[i]) == 0) {
01828 act = (LogFilter::Action) i;
01829 break;
01830 }
01831 }
01832
01833 if (i == LogFilter::N_ACTIONS) {
01834 Warning("%s is not a valid filter action value; cannot create filter %s.", action_str, filter_name);
01835 continue;
01836 }
01837
01838
01839 char *cond_str = condition.dequeue();
01840
01841 SimpleTokenizer tok(cond_str);
01842
01843 if (tok.getNumTokensRemaining() < 3) {
01844 Warning("Invalid condition syntax \"%s\"; cannot create filter %s.", cond_str, filter_name);
01845 continue;
01846 }
01847
01848 char *field_str = tok.getNext();
01849 char *oper_str = tok.getNext();
01850 char *val_str = tok.getRest();
01851
01852
01853
01854 if (strlen(field_str) > 2 && field_str[0] == '%' && field_str[1] == '<') {
01855 Debug("xml", "Field symbol has <> form: %s", field_str);
01856 char *end = field_str;
01857 while (*end && *end != '>')
01858 end++;
01859 *end = '\0';
01860 field_str += 2;
01861 Debug("xml", "... now field symbol is %s", field_str);
01862 }
01863
01864 LogField *logfield = Log::global_field_list.find_by_symbol(field_str);
01865 if (!logfield) {
01866
01867 if (*field_str == '{') {
01868 Note("%s appears to be a container field", field_str);
01869 char *fname_end = strchr(field_str, '}');
01870 if (NULL != fname_end) {
01871 char *fname = field_str + 1;
01872 *fname_end = 0;
01873 char *cname = fname_end + 1;
01874 Note("Found Container Field: Name = %s, symbol = %s", fname, cname);
01875 LogField::Container container = LogField::valid_container_name(cname);
01876 if (container == LogField::NO_CONTAINER) {
01877 Warning("%s is not a valid container; cannot create filter %s.", cname, filter_name);
01878 continue;
01879 } else {
01880 logfield = new LogField(fname, container);
01881 ink_assert(logfield != NULL);
01882 }
01883 } else {
01884 Warning("Invalid container field specification: no trailing '}' in %s cannot create filter %s.", field_str, filter_name);
01885 continue;
01886 }
01887 }
01888 }
01889
01890 if (!logfield) {
01891 Warning("%s is not a valid field; cannot create filter %s.", field_str, filter_name);
01892 continue;
01893 }
01894
01895
01896 LogFilter::Operator oper = LogFilter::MATCH;
01897 for (i = 0; i < LogFilter::N_OPERATORS; ++i) {
01898 if (strcasecmp(oper_str, LogFilter::OPERATOR_NAME[i]) == 0) {
01899 oper = (LogFilter::Operator) i;
01900 break;
01901 }
01902 }
01903
01904 if (i == LogFilter::N_OPERATORS) {
01905 Warning("%s is not a valid operator; cannot create filter %s.", oper_str, filter_name);
01906 continue;
01907 }
01908
01909
01910 LogFilter *filter = NULL;
01911 LogField::Type field_type = logfield->type();
01912
01913 switch (field_type) {
01914
01915 case LogField::sINT:
01916
01917 filter = new LogFilterInt(filter_name, logfield, act, oper, val_str);
01918 break;
01919
01920 case LogField::dINT:
01921
01922 Warning("Internal error: invalid field type (double int); cannot create filter %s.", filter_name);
01923 continue;
01924
01925 case LogField::STRING:
01926
01927 filter = new LogFilterString(filter_name, logfield, act, oper, val_str);
01928 break;
01929
01930 case LogField::IP:
01931
01932 filter = new LogFilterIP(filter_name, logfield, act, oper, val_str);
01933 break;
01934
01935 default:
01936
01937 Warning("Internal error: unknown field type %d; cannot create filter %s.", field_type, filter_name);
01938 continue;
01939 }
01940
01941 ink_assert(filter);
01942
01943 if (filter->get_num_values() == 0) {
01944
01945 Warning("\"%s\" does not specify any valid values; cannot create filter %s.", val_str, filter_name);
01946 delete filter;
01947
01948 } else {
01949
01950
01951
01952 global_filter_list.add(filter, false);
01953
01954 if (is_debug_tag_set("xml")) {
01955 printf("The following filter was added to the global filter list\n");
01956 filter->display_as_XML();
01957 }
01958 }
01959 }
01960
01961 else if (strcasecmp(xobj->object_name(), "LogObject") == 0) {
01962
01963 NameList format;
01964 NameList filename;
01965 NameList mode;
01966 NameList filters;
01967 NameList protocols;
01968 NameList serverHosts;
01969 NameList collationHosts;
01970 NameList header;
01971 NameList rollingEnabled;
01972 NameList rollingIntervalSec;
01973 NameList rollingOffsetHr;
01974 NameList rollingSizeMb;
01975
01976 for (xattr = xobj->first(); xattr; xattr = xobj->next(xattr)) {
01977 Debug("xml", "XmlAttr : <%s,%s>", xattr->tag(), xattr->value());
01978 if (strcasecmp(xattr->tag(), "Format") == 0) {
01979 format.enqueue(xattr->value());
01980 } else if (strcasecmp(xattr->tag(), "Filename") == 0) {
01981 filename.enqueue(xattr->value());
01982 } else if (strcasecmp(xattr->tag(), "Mode") == 0) {
01983 mode.enqueue(xattr->value());
01984 } else if (strcasecmp(xattr->tag(), "Filters") == 0) {
01985 filters.enqueue(xattr->value());
01986 } else if (strcasecmp(xattr->tag(), "Protocols") == 0) {
01987 protocols.enqueue(xattr->value());
01988 } else if (strcasecmp(xattr->tag(), "ServerHosts") == 0) {
01989 serverHosts.enqueue(xattr->value());
01990 } else if (strcasecmp(xattr->tag(), "CollationHosts") == 0) {
01991 collationHosts.enqueue(xattr->value());
01992 } else if (strcasecmp(xattr->tag(), "Header") == 0) {
01993 header.enqueue(xattr->value());
01994 } else if (strcasecmp(xattr->tag(), "RollingEnabled") == 0) {
01995 rollingEnabled.enqueue(xattr->value());
01996 } else if (strcasecmp(xattr->tag(), "RollingIntervalSec") == 0) {
01997 rollingIntervalSec.enqueue(xattr->value());
01998 } else if (strcasecmp(xattr->tag(), "RollingOffsetHr") == 0) {
01999 rollingOffsetHr.enqueue(xattr->value());
02000 } else if (strcasecmp(xattr->tag(), "RollingSizeMb") == 0) {
02001 rollingSizeMb.enqueue(xattr->value());
02002 } else {
02003 Note("Unknown attribute %s for %s; ignoring", xattr->tag(), xobj->object_name());
02004 }
02005 }
02006
02007
02008
02009 if (format.count() == 0) {
02010 Note("'Format' attribute missing for LogObject object");
02011 continue;
02012 }
02013 if (filename.count() == 0) {
02014 Note("'Filename' attribute missing for LogObject object");
02015 continue;
02016 }
02017
02018 if (format.count() > 1) {
02019 Note("Multiple values for 'Format' attribute in %s; using the first one", xobj->object_name());
02020 }
02021 if (filename.count() > 1) {
02022 Note("Multiple values for 'Filename' attribute in %s; using the first one", xobj->object_name());
02023 }
02024 if (mode.count() > 1) {
02025 Note("Multiple values for 'Mode' attribute in %s; using the first one", xobj->object_name());
02026 }
02027 if (filters.count() > 1) {
02028 Note("Multiple values for 'Filters' attribute in %s; using the first one", xobj->object_name());
02029 }
02030 if (protocols.count() > 1) {
02031 Note("Multiple values for 'Protocols' attribute in %s; using the first one", xobj->object_name());
02032 }
02033 if (serverHosts.count() > 1) {
02034 Note("Multiple values for 'ServerHosts' attribute in %s; using the first one", xobj->object_name());
02035 }
02036 if (collationHosts.count() > 1) {
02037 Note("Multiple values for 'CollationHosts' attribute in %s; using the first one", xobj->object_name());
02038 }
02039 if (header.count() > 1) {
02040 Note("Multiple values for 'Header' attribute in %s; using the first one", xobj->object_name());
02041 }
02042 if (rollingEnabled.count() > 1) {
02043 Note("Multiple values for 'RollingEnabled' attribute in %s; using the first one", xobj->object_name());
02044 }
02045 if (rollingIntervalSec.count() > 1) {
02046 Note("Multiple values for 'RollingIntervalSec' attribute in %s; using the first one", xobj->object_name());
02047 }
02048 if (rollingOffsetHr.count() > 1) {
02049 Note("Multiple values for 'RollingOffsetHr' attribute in %s; using the first one", xobj->object_name());
02050 }
02051 if (rollingSizeMb.count() > 1) {
02052 Note("Multiple values for 'RollingSizeMb' attribute in %s; using the first one", xobj->object_name());
02053 }
02054
02055
02056
02057 char *fmt_name = format.dequeue();
02058 LogFormat *fmt = global_format_list.find_by_name(fmt_name);
02059 if (!fmt) {
02060 Warning("Format %s not in the global format list; cannot create LogObject", fmt_name);
02061 continue;
02062 }
02063
02064
02065 LogFileFormat file_type = LOG_FILE_ASCII;
02066 if (mode.count()) {
02067 char *mode_str = mode.dequeue();
02068 file_type = (strncasecmp(mode_str, "bin", 3) == 0 ||
02069 (mode_str[0] == 'b' && mode_str[1] == 0) ?
02070 LOG_FILE_BINARY : (strcasecmp(mode_str, "ascii_pipe") == 0 ? LOG_FILE_PIPE : LOG_FILE_ASCII));
02071 }
02072
02073
02074 char *rollingEnabled_str = rollingEnabled.dequeue();
02075 int obj_rolling_enabled = rollingEnabled_str ? ink_atoui(rollingEnabled_str) : rolling_enabled;
02076
02077 char *rollingIntervalSec_str = rollingIntervalSec.dequeue();
02078 int obj_rolling_interval_sec = rollingIntervalSec_str ? ink_atoui(rollingIntervalSec_str) : rolling_interval_sec;
02079
02080 char *rollingOffsetHr_str = rollingOffsetHr.dequeue();
02081 int obj_rolling_offset_hr = rollingOffsetHr_str ? ink_atoui(rollingOffsetHr_str) : rolling_offset_hr;
02082
02083 char *rollingSizeMb_str = rollingSizeMb.dequeue();
02084 int obj_rolling_size_mb = rollingSizeMb_str ? ink_atoui(rollingSizeMb_str) : rolling_size_mb;
02085
02086 if (!LogRollingEnabledIsValid(obj_rolling_enabled)) {
02087 Warning("Invalid log rolling value '%d' in log object %s", obj_rolling_enabled, xobj->object_name());
02088 }
02089
02090
02091
02092 LogObject *obj = new LogObject(fmt, logfile_dir,
02093 filename.dequeue(),
02094 file_type,
02095 header.dequeue(),
02096 (Log::RollingEnabledValues)obj_rolling_enabled,
02097 collation_preproc_threads,
02098 obj_rolling_interval_sec,
02099 obj_rolling_offset_hr,
02100 obj_rolling_size_mb);
02101
02102
02103
02104 char *filters_str = filters.dequeue();
02105 if (filters_str) {
02106 SimpleTokenizer tok(filters_str, ',');
02107 char *filter_name;
02108 while (filter_name = tok.getNext(), filter_name != 0) {
02109 LogFilter *f;
02110 f = global_filter_list.find_by_name(filter_name);
02111 if (!f) {
02112 Warning("Filter %s not in the global filter list; cannot add to this LogObject", filter_name);
02113 } else {
02114 obj->add_filter(f);
02115 }
02116 }
02117 }
02118
02119
02120 char *protocols_str = protocols.dequeue();
02121 if (protocols_str) {
02122
02123 LogField *etype_field = Log::global_field_list.find_by_symbol("etype");
02124 ink_assert(etype_field);
02125
02126 SimpleTokenizer tok(protocols_str, ',');
02127 size_t n = tok.getNumTokensRemaining();
02128
02129 if (n) {
02130 int64_t *val_array = new int64_t[n];
02131 size_t numValid = 0;
02132 char *t;
02133 while (t = tok.getNext(), t != NULL) {
02134 if (strcasecmp(t, "icp") == 0) {
02135 val_array[numValid++] = LOG_ENTRY_ICP;
02136 } else if (strcasecmp(t, "http") == 0) {
02137 val_array[numValid++] = LOG_ENTRY_HTTP;
02138 }
02139 }
02140
02141 if (numValid == 0) {
02142 Warning("No valid protocol value(s) (%s) for Protocol "
02143 "field in definition of XML LogObject.\nObject will log all protocols.", protocols_str);
02144 } else {
02145 if (numValid < n) {
02146 Warning("There are invalid protocol values (%s) in"
02147 " the Protocol field of XML LogObject.\n"
02148 "Only %zu out of %zu values will be used.", protocols_str, numValid, n);
02149 }
02150
02151 LogFilterInt protocol_filter("__xml_protocol__",
02152 etype_field, LogFilter::ACCEPT, LogFilter::MATCH, numValid, val_array);
02153 obj->add_filter(&protocol_filter);
02154 }
02155 delete[] val_array;
02156 } else {
02157 Warning("No value(s) in Protocol field of XML object, object will log all protocols.");
02158 }
02159 }
02160
02161
02162 char *serverHosts_str = serverHosts.dequeue();
02163 if (serverHosts_str) {
02164
02165 LogField *shn_field = Log::global_field_list.find_by_symbol("shn");
02166 ink_assert(shn_field);
02167
02168 LogFilterString server_host_filter("__xml_server_hosts__",
02169 shn_field, LogFilter::ACCEPT, LogFilter::CASE_INSENSITIVE_CONTAIN, serverHosts_str);
02170
02171 if (server_host_filter.get_num_values() == 0) {
02172 Warning("No valid server host value(s) (%s) for Protocol "
02173 "field in definition of XML LogObject.\nObject will log all servers.", serverHosts_str);
02174 } else {
02175 obj->add_filter(&server_host_filter);
02176 }
02177 }
02178
02179
02180 char *collationHosts_str = collationHosts.dequeue();
02181 if (collationHosts_str) {
02182 char *host;
02183 SimpleTokenizer tok(collationHosts_str, ',');
02184 while (host = tok.getNext(), host != 0) {
02185
02186 LogHost *prev = NULL;
02187 char *failover_str;
02188 SimpleTokenizer failover_tok(host, '|');
02189
02190 while (failover_str = failover_tok.getNext(), failover_str != 0) {
02191 LogHost *lh = new LogHost(obj->get_full_filename(), obj->get_signature());
02192
02193 if (lh->set_name_or_ipstr(failover_str)) {
02194 Warning("Could not set \"%s\" as collation host", host);
02195 delete lh;
02196 } else if (!prev){
02197 obj->add_loghost(lh, false);
02198 prev = lh;
02199 } else {
02200 prev->failover_link.next = lh;
02201 prev = lh;
02202 }
02203 }
02204 }
02205 }
02206
02207
02208 log_object_manager.manage_object(obj);
02209 }
02210
02211 else {
02212 Note("Unknown XML config object for logging: %s", xobj->object_name());
02213 }
02214 }
02215 }
02216
02217
02218
02219
02220
02221
02222
02223
02224
02225 char **
02226 LogConfig::read_log_hosts_file(size_t * num_hosts)
02227 {
02228 ats_scoped_str config_path(Layout::get()->relative_to(Layout::get()->sysconfdir, hosts_config_file));
02229 char line[LOG_MAX_FORMAT_LINE];
02230 char **hosts = NULL;
02231
02232 Debug("log-config", "Reading log hosts from %s", (const char *)config_path);
02233
02234 size_t nhosts = 0;
02235 int fd = open(config_path, O_RDONLY);
02236 if (fd < 0) {
02237 Warning("Traffic Server can't open %s for reading log hosts for splitting: %s.", (const char *)config_path, strerror(errno));
02238 } else {
02239
02240
02241
02242 while (ink_file_fd_readline(fd, LOG_MAX_FORMAT_LINE, line) > 0) {
02243
02244
02245
02246 if (*line == '\n' || *line == '#') {
02247 continue;
02248 }
02249 ++nhosts;
02250 }
02251
02252
02253
02254 if (nhosts) {
02255 if (lseek(fd, 0, SEEK_SET) != 0) {
02256 Warning("lseek failed on file %s: %s", (const char *)config_path, strerror(errno));
02257 nhosts = 0;
02258 } else {
02259 hosts = new char *[nhosts];
02260 ink_assert(hosts != NULL);
02261
02262 size_t i = 0;
02263 while (ink_file_fd_readline(fd, LOG_MAX_FORMAT_LINE, line) > 0) {
02264
02265
02266
02267 if (*line == '\n' || *line == '#') {
02268 continue;
02269 }
02270 LogUtils::strip_trailing_newline(line);
02271 hosts[i] = ats_strdup(line);
02272 ++i;
02273 }
02274 ink_assert(i == nhosts);
02275 }
02276 }
02277 close(fd);
02278 }
02279 *num_hosts = nhosts;
02280 return hosts;
02281 }