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 }