00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "libts.h"
00030
00031
00032 #include "Error.h"
00033 #include "P_EventSystem.h"
00034 #include "LogUtils.h"
00035 #include "LogField.h"
00036 #include "LogObject.h"
00037 #include "LogConfig.h"
00038 #include "LogAccess.h"
00039 #include "Log.h"
00040 #include "ts/TestBox.h"
00041
00042 static bool
00043 should_roll_on_time(Log::RollingEnabledValues roll) {
00044 return roll == Log::ROLL_ON_TIME_ONLY || roll == Log::ROLL_ON_TIME_OR_SIZE;
00045 }
00046
00047 static bool
00048 should_roll_on_size(Log::RollingEnabledValues roll) {
00049 return roll == Log::ROLL_ON_SIZE_ONLY || roll == Log::ROLL_ON_TIME_OR_SIZE;
00050 }
00051
00052 size_t
00053 LogBufferManager::preproc_buffers(LogBufferSink *sink) {
00054 SList(LogBuffer, write_link) q(write_list.popall()), new_q;
00055 LogBuffer *b = NULL;
00056 while ((b = q.pop())) {
00057 if (b->m_references || b->m_state.s.num_writers) {
00058
00059 write_list.push(b);
00060 } else if (_num_flush_buffers > FLUSH_ARRAY_SIZE) {
00061 ink_atomic_increment(&_num_flush_buffers, -1);
00062 Warning("Dropping log buffer, can't keep up.");
00063 RecIncrRawStat(log_rsb, this_thread()->mutex->thread_holding,
00064 log_stat_bytes_lost_before_preproc_stat,
00065 b->header()->byte_count);
00066 delete b;
00067 } else {
00068 new_q.push(b);
00069 }
00070 }
00071
00072 int prepared = 0;
00073 while ((b = new_q.pop())) {
00074 b->update_header_data();
00075 sink->preproc_and_try_delete(b);
00076 ink_atomic_increment(&_num_flush_buffers, -1);
00077 prepared++;
00078 }
00079
00080 Debug("log-logbuffer", "prepared %d buffers", prepared);
00081 return prepared;
00082 }
00083
00084
00085
00086
00087
00088 LogObject::LogObject(const LogFormat *format, const char *log_dir,
00089 const char *basename, LogFileFormat file_format,
00090 const char *header, Log::RollingEnabledValues rolling_enabled,
00091 int flush_threads, int rolling_interval_sec,
00092 int rolling_offset_hr, int rolling_size_mb,
00093 bool auto_created):
00094 m_auto_created(auto_created),
00095 m_alt_filename (NULL),
00096 m_flags (0),
00097 m_signature (0),
00098 m_flush_threads (flush_threads),
00099 m_rolling_interval_sec (rolling_interval_sec),
00100 m_rolling_offset_hr (rolling_offset_hr),
00101 m_rolling_size_mb (rolling_size_mb),
00102 m_last_roll_time(0),
00103 m_buffer_manager_idx(0)
00104 {
00105 ink_assert (format != NULL);
00106 m_format = new LogFormat(*format);
00107 m_buffer_manager = new LogBufferManager[m_flush_threads];
00108
00109 if (file_format == LOG_FILE_BINARY) {
00110 m_flags |= BINARY;
00111 } else if (file_format == LOG_FILE_PIPE) {
00112 m_flags |= WRITES_TO_PIPE;
00113 }
00114
00115 generate_filenames(log_dir, basename, file_format);
00116
00117
00118 m_signature = compute_signature(m_format, m_basename, m_flags);
00119
00120
00121
00122
00123 m_logFile = new LogFile(m_filename, header, file_format,
00124 m_signature,
00125 Log::config->ascii_buffer_size,
00126 Log::config->max_line_size);
00127
00128 LogBuffer *b = new LogBuffer (this, Log::config->log_buffer_size);
00129 ink_assert(b);
00130 SET_FREELIST_POINTER_VERSION(m_log_buffer, b, 0);
00131
00132 _setup_rolling(rolling_enabled, rolling_interval_sec, rolling_offset_hr, rolling_size_mb);
00133
00134 Debug("log-config", "exiting LogObject constructor, filename=%s this=%p",
00135 m_filename, this);
00136 }
00137
00138 LogObject::LogObject(LogObject& rhs)
00139 : m_basename(ats_strdup(rhs.m_basename)),
00140 m_filename(ats_strdup(rhs.m_filename)),
00141 m_alt_filename(ats_strdup(rhs.m_alt_filename)),
00142 m_flags(rhs.m_flags),
00143 m_signature(rhs.m_signature),
00144 m_flush_threads(rhs.m_flush_threads),
00145 m_rolling_interval_sec(rhs.m_rolling_interval_sec),
00146 m_last_roll_time(rhs.m_last_roll_time)
00147 {
00148 m_format = new LogFormat(*(rhs.m_format));
00149 m_buffer_manager = new LogBufferManager[m_flush_threads];
00150
00151 if (rhs.m_logFile) {
00152 m_logFile = new LogFile(*(rhs.m_logFile));
00153 } else {
00154 m_logFile = NULL;
00155 }
00156
00157 LogFilter *filter;
00158 for (filter = rhs.m_filter_list.first(); filter;
00159 filter = rhs.m_filter_list.next (filter)) {
00160 add_filter (filter);
00161 }
00162
00163 LogHost *host;
00164 for (host = rhs.m_host_list.first(); host;
00165 host = rhs.m_host_list.next (host)) {
00166 add_loghost (host);
00167 }
00168
00169
00170
00171 LogBuffer *b = new LogBuffer (this, Log::config->log_buffer_size);
00172 ink_assert(b);
00173 SET_FREELIST_POINTER_VERSION(m_log_buffer, b, 0);
00174
00175 Debug("log-config", "exiting LogObject copy constructor, "
00176 "filename=%s this=%p", m_filename, this);
00177 }
00178
00179 LogObject::~LogObject()
00180 {
00181 Debug("log-config", "entering LogObject destructor, this=%p", this);
00182
00183 preproc_buffers();
00184
00185
00186 if (is_collation_client()) {
00187 if (m_host_list.count()) {
00188 m_host_list.clear();
00189 }
00190 }
00191 ats_free(m_basename);
00192 ats_free(m_filename);
00193 ats_free(m_alt_filename);
00194 delete m_format;
00195 delete[] m_buffer_manager;
00196 delete (LogBuffer*)FREELIST_POINTER(m_log_buffer);
00197 }
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 void
00212 LogObject::generate_filenames(const char *log_dir, const char *basename, LogFileFormat file_format)
00213 {
00214 ink_assert(log_dir && basename);
00215
00216 int i = -1, len = 0;
00217 char c;
00218 while (c = basename[len], c != 0) {
00219 if (c == '.') {
00220 i = len;
00221 }
00222 ++len;
00223 }
00224 if (i == len - 1) {
00225 --len;
00226 };
00227
00228 const char *ext = 0;
00229 int ext_len = 0;
00230 if (i < 0) {
00231 switch (file_format) {
00232 case LOG_FILE_ASCII:
00233 ext = LOG_FILE_ASCII_OBJECT_FILENAME_EXTENSION;
00234 ext_len = 4;
00235 break;
00236 case LOG_FILE_BINARY:
00237 ext = LOG_FILE_BINARY_OBJECT_FILENAME_EXTENSION;
00238 ext_len = 5;
00239 break;
00240 case LOG_FILE_PIPE:
00241 ext = LOG_FILE_PIPE_OBJECT_FILENAME_EXTENSION;
00242 ext_len = 5;
00243 break;
00244 default:
00245 ink_assert(!"unknown file format");
00246 }
00247 }
00248
00249 int dir_len = (int) strlen(log_dir);
00250 int basename_len = len + ext_len + 1;
00251 int total_len = dir_len + 1 + basename_len;
00252
00253 m_filename = (char *)ats_malloc(total_len);
00254 m_basename = (char *)ats_malloc(basename_len);
00255
00256 memcpy(m_filename, log_dir, dir_len);
00257 m_filename[dir_len++] = '/';
00258 memcpy(&m_filename[dir_len], basename, len);
00259 memcpy(m_basename, basename, len);
00260
00261 if (ext_len) {
00262 memcpy(&m_filename[dir_len + len], ext, ext_len);
00263 memcpy(&m_basename[len], ext, ext_len);
00264 }
00265 m_filename[total_len - 1] = 0;
00266 m_basename[basename_len - 1] = 0;
00267 }
00268
00269
00270
00271 void
00272 LogObject::rename(char *new_name)
00273 {
00274
00275
00276
00277
00278 ats_free(m_alt_filename);
00279 m_alt_filename = ats_strdup(new_name);
00280 m_logFile->change_name(new_name);
00281 }
00282
00283
00284 void
00285 LogObject::add_filter(LogFilter * filter, bool copy)
00286 {
00287 if (!filter) {
00288 return;
00289 }
00290 m_filter_list.add(filter, copy);
00291 }
00292
00293
00294 void
00295 LogObject::set_filter_list(const LogFilterList & list, bool copy)
00296 {
00297 LogFilter *f;
00298
00299 m_filter_list.clear();
00300 for (f = list.first(); f != NULL; f = list.next(f)) {
00301 m_filter_list.add(f, copy);
00302 }
00303 m_filter_list.set_conjunction(list.does_conjunction());
00304 }
00305
00306
00307 void
00308 LogObject::add_loghost(LogHost * host, bool copy)
00309 {
00310 if (!host) {
00311 return;
00312 }
00313 m_host_list.add(host, copy);
00314
00315
00316
00317
00318
00319 m_logFile.clear();
00320 }
00321
00322
00323
00324
00325
00326
00327 uint64_t LogObject::compute_signature(LogFormat * format, char *filename, unsigned int flags)
00328 {
00329 char *fl = format->fieldlist();
00330 char *ps = format->printf_str();
00331 uint64_t signature = 0;
00332
00333 if (fl && ps && filename) {
00334 int buf_size = strlen(fl) + strlen(ps) + strlen(filename) + 2;
00335 char *buffer = (char *)ats_malloc(buf_size);
00336
00337 ink_string_concatenate_strings(buffer, fl, ps, filename, flags & LogObject::BINARY ? "B" :
00338 (flags & LogObject::WRITES_TO_PIPE ? "P" : "A"), NULL);
00339
00340 CryptoHash hash;
00341 MD5Context().hash_immediate(hash, buffer, buf_size - 1);
00342 signature = hash.fold();
00343
00344 ats_free(buffer);
00345 }
00346 return signature;
00347 }
00348
00349
00350 void
00351 LogObject::display(FILE * fd)
00352 {
00353 fprintf(fd, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
00354 fprintf(fd, "LogObject [%p]: format = %s (%p)\nbasename = %s\n" "flags = %u\n"
00355 "signature = %" PRIu64 "\n",
00356 this, m_format->name(), m_format, m_basename, m_flags, m_signature);
00357 if (is_collation_client()) {
00358 m_host_list.display(fd);
00359 } else {
00360 fprintf(fd, "full path = %s\n", get_full_filename());
00361 }
00362 m_filter_list.display(fd);
00363 fprintf(fd, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
00364 }
00365
00366
00367 void
00368 LogObject::displayAsXML(FILE * fd, bool extended)
00369 {
00370 if (extended) {
00371
00372 m_format->displayAsXML(fd);
00373 m_filter_list.display_as_XML(fd);
00374 }
00375
00376 fprintf(fd,
00377 "<LogObject>\n"
00378 " <Mode = \"%s\"/>\n"
00379 " <Format = \"%s\"/>\n"
00380 " <Filename = \"%s\"/>\n", (m_flags & BINARY ? "binary" : "ascii"), m_format->name(), m_filename);
00381
00382 LogFilter *filter;
00383 for (filter = m_filter_list.first(); filter != NULL; filter = m_filter_list.next(filter)) {
00384 fprintf(fd, " <Filter = \"%s\"/>\n", filter->name());
00385 }
00386
00387 LogHost *host;
00388 for (host = m_host_list.first(); host != NULL; host = m_host_list.next(host)) {
00389 fprintf(fd, " <LogHostName = \"%s\"/>\n", host->name());
00390 }
00391
00392 fprintf(fd, "</LogObject>\n");
00393 }
00394
00395
00396 LogBuffer *
00397 LogObject::_checkout_write(size_t * write_offset, size_t bytes_needed) {
00398 LogBuffer::LB_ResultCode result_code;
00399 LogBuffer *buffer;
00400 LogBuffer *new_buffer;
00401 bool retry = true;
00402
00403 do {
00404
00405
00406 head_p h;
00407 int result = 0;
00408 do {
00409 INK_QUEUE_LD(h, m_log_buffer);
00410 head_p new_h;
00411 SET_FREELIST_POINTER_VERSION(new_h, FREELIST_POINTER(h), FREELIST_VERSION(h) + 1);
00412 #if TS_HAS_128BIT_CAS
00413 result = ink_atomic_cas((__int128_t*) &m_log_buffer.data, h.data, new_h.data);
00414 #else
00415 result = ink_atomic_cas((int64_t *) &m_log_buffer.data, h.data, new_h.data);
00416 #endif
00417 } while (!result);
00418 buffer = (LogBuffer*)FREELIST_POINTER(h);
00419 result_code = buffer->checkout_write(write_offset, bytes_needed);
00420 bool decremented = false;
00421
00422 switch (result_code) {
00423 case LogBuffer::LB_OK:
00424
00425
00426 retry = false;
00427 break;
00428
00429 case LogBuffer::LB_FULL_ACTIVE_WRITERS:
00430 case LogBuffer::LB_FULL_NO_WRITERS:
00431
00432 new_buffer = new LogBuffer(this, Log::config->log_buffer_size);
00433
00434
00435 INK_WRITE_MEMORY_BARRIER;
00436 head_p old_h;
00437 do {
00438 INK_QUEUE_LD(old_h, m_log_buffer);
00439 if (FREELIST_POINTER(old_h) != FREELIST_POINTER(h)) {
00440 ink_atomic_increment(&buffer->m_references, -1);
00441
00442
00443
00444 delete new_buffer;
00445 break;
00446 }
00447 head_p tmp_h;
00448 SET_FREELIST_POINTER_VERSION(tmp_h, new_buffer, 0);
00449 #if TS_HAS_128BIT_CAS
00450 result = ink_atomic_cas((__int128_t*) &m_log_buffer.data, old_h.data, tmp_h.data);
00451 #else
00452 result = ink_atomic_cas((int64_t *) &m_log_buffer.data, old_h.data, tmp_h.data);
00453 #endif
00454 } while (!result);
00455 if (FREELIST_POINTER(old_h) == FREELIST_POINTER(h)) {
00456 ink_atomic_increment(&buffer->m_references, FREELIST_VERSION(old_h) - 1);
00457
00458 int idx = m_buffer_manager_idx++ % m_flush_threads;
00459 Debug("log-logbuffer", "adding buffer %d to flush list after checkout", buffer->get_id());
00460 m_buffer_manager[idx].add_to_flush_queue(buffer);
00461 Log::preproc_notify[idx].signal();
00462
00463 }
00464 decremented = true;
00465 break;
00466
00467 case LogBuffer::LB_RETRY:
00468
00469
00470
00471 break;
00472
00473 case LogBuffer::LB_BUFFER_TOO_SMALL:
00474
00475
00476
00477
00478 retry = false;
00479 buffer = NULL;
00480 break;
00481
00482 default:
00483 ink_assert(false);
00484 }
00485 if (!decremented) {
00486 head_p old_h;
00487 do {
00488 INK_QUEUE_LD(old_h, m_log_buffer);
00489 if (FREELIST_POINTER(old_h) != FREELIST_POINTER(h))
00490 break;
00491 head_p tmp_h;
00492 SET_FREELIST_POINTER_VERSION(tmp_h, FREELIST_POINTER(h), FREELIST_VERSION(old_h) - 1);
00493 #if TS_HAS_128BIT_CAS
00494 result = ink_atomic_cas((__int128_t*) &m_log_buffer.data, old_h.data, tmp_h.data);
00495 #else
00496 result = ink_atomic_cas((int64_t *) &m_log_buffer.data, old_h.data, tmp_h.data);
00497 #endif
00498 } while (!result);
00499 if (FREELIST_POINTER(old_h) != FREELIST_POINTER(h))
00500 ink_atomic_increment(&buffer->m_references, -1);
00501 }
00502 } while (retry && write_offset);
00503
00504
00505
00506
00507 return buffer;
00508 }
00509
00510
00511 int
00512 LogObject::va_log(LogAccess * lad, const char * fmt, va_list ap)
00513 {
00514 static const unsigned MAX_ENTRY = 16 * LOG_KILOBYTE;
00515 char entry[MAX_ENTRY];
00516 unsigned len = 0;
00517
00518 ink_assert(fmt != NULL);
00519 len = 0;
00520
00521 if (this->m_flags & LOG_OBJECT_FMT_TIMESTAMP) {
00522 len = LogUtils::timestamp_to_str(LogUtils::timestamp(), entry, MAX_ENTRY);
00523 if (len <= 0) {
00524 return Log::FAIL;
00525 }
00526
00527
00528 entry[len++] = ' ';
00529
00530 if (len >= MAX_ENTRY) {
00531 return Log::FAIL;
00532 }
00533 }
00534
00535 vsnprintf(&entry[len], MAX_ENTRY - len, fmt, ap);
00536
00537
00538
00539 return this->log(lad, entry);
00540 }
00541
00542 int
00543 LogObject::log(LogAccess * lad, const char *text_entry)
00544 {
00545 LogBuffer *buffer;
00546 size_t offset = 0;
00547 size_t bytes_needed = 0, bytes_used = 0;
00548
00549
00550
00551
00552 if (Log::config->logging_space_exhausted && !writes_to_pipe() && m_logFile) {
00553 Debug("log", "logging space exhausted, can't write to:%s, drop this entry", m_logFile->get_name());
00554 return Log::FULL;
00555 }
00556
00557
00558 if (!lad && !text_entry) {
00559 Note("Call to LogAccess without LAD or text entry; skipping");
00560 return Log::FAIL;
00561 }
00562
00563 if (lad && m_filter_list.toss_this_entry(lad)) {
00564 Debug("log", "entry filtered, skipping ...");
00565 return Log::SKIP;
00566 }
00567
00568 if (lad && m_filter_list.wipe_this_entry(lad)) {
00569 Debug("log", "entry wiped, ...");
00570 }
00571
00572 if (lad && m_format->is_aggregate()) {
00573
00574
00575 if (m_format->m_agg_marshal_space == NULL) {
00576 Note("No temp space to marshal aggregate fields into");
00577 return Log::FAIL;
00578 }
00579
00580 long time_now = LogUtils::timestamp();
00581 m_format->m_field_list.marshal(lad, m_format->m_agg_marshal_space);
00582
00583
00584
00585 LogFieldList *fl = &m_format->m_field_list;
00586 char *data_ptr = m_format->m_agg_marshal_space;
00587 LogField *f;
00588 int64_t val;
00589 for (f = fl->first(); f; f = fl->next(f)) {
00590
00591
00592 val = (f->is_time_field())? time_now : *((int64_t *) data_ptr);
00593 f->update_aggregate(val);
00594 data_ptr += INK_MIN_ALIGN;
00595 }
00596
00597 if (time_now < m_format->m_interval_next) {
00598 Debug("log-agg", "Time now = %ld, next agg = %ld; not time "
00599 "for aggregate entry", time_now, m_format->m_interval_next);
00600 return Log::AGGR;
00601 }
00602
00603
00604 bytes_needed = m_format->field_count() * INK_MIN_ALIGN;
00605 } else if (lad) {
00606 bytes_needed = m_format->m_field_list.marshal_len(lad);
00607 } else if (text_entry) {
00608 bytes_needed = LogAccess::strlen(text_entry);
00609 }
00610
00611 if (bytes_needed == 0) {
00612 Debug("log-buffer", "Nothing to log, bytes_needed = 0");
00613 return Log::SKIP;
00614 }
00615
00616
00617 buffer = _checkout_write(&offset, bytes_needed);
00618
00619 if (!buffer) {
00620 Note("Skipping the current log entry for %s because its size (%zu) exceeds "
00621 "the maximum payload space in a log buffer", m_basename, bytes_needed);
00622 return Log::FAIL;
00623 }
00624
00625
00626
00627
00628
00629
00630 if (lad && m_format->is_aggregate()) {
00631
00632
00633 bytes_used = m_format->m_field_list.marshal_agg(&(*buffer)[offset]);
00634 ink_assert(bytes_needed >= bytes_used);
00635 m_format->m_interval_next += m_format->m_interval_sec;
00636 Debug("log-agg", "Aggregate entry created; next time is %ld", m_format->m_interval_next);
00637 } else if (lad) {
00638 bytes_used = m_format->m_field_list.marshal(lad, &(*buffer)[offset]);
00639 ink_assert(bytes_needed >= bytes_used);
00640 } else if (text_entry) {
00641 ink_strlcpy(&(*buffer)[offset], text_entry, bytes_needed);
00642 }
00643
00644 buffer->checkin_write(offset);
00645
00646 return Log::LOG_OK;
00647 }
00648
00649
00650 void
00651 LogObject::_setup_rolling(Log::RollingEnabledValues rolling_enabled, int rolling_interval_sec, int rolling_offset_hr, int rolling_size_mb)
00652 {
00653 if (!LogRollingEnabledIsValid((int)rolling_enabled)) {
00654 m_rolling_enabled = Log::NO_ROLLING;
00655 m_rolling_interval_sec = 0;
00656 m_rolling_offset_hr = 0;
00657 m_rolling_size_mb = 0;
00658 if (rolling_enabled != Log::NO_ROLLING) {
00659 Warning("Valid rolling_enabled values are %d to %d, invalid value "
00660 "(%d) specified for %s, rolling will be disabled for this file.",
00661 Log::NO_ROLLING, Log::INVALID_ROLLING_VALUE - 1, rolling_enabled, m_filename);
00662 } else {
00663 Status("Rolling disabled for %s", m_filename);
00664 }
00665 } else {
00666
00667
00668 if (rolling_enabled == Log::ROLL_ON_TIME_ONLY ||
00669 rolling_enabled == Log::ROLL_ON_TIME_OR_SIZE || rolling_enabled == Log::ROLL_ON_TIME_AND_SIZE) {
00670 if (rolling_interval_sec < Log::MIN_ROLLING_INTERVAL_SEC) {
00671
00672 m_rolling_interval_sec = Log::MIN_ROLLING_INTERVAL_SEC;
00673 } else if (rolling_interval_sec > Log::MAX_ROLLING_INTERVAL_SEC) {
00674
00675 m_rolling_interval_sec = Log::MAX_ROLLING_INTERVAL_SEC;
00676 } else if (Log::MAX_ROLLING_INTERVAL_SEC % rolling_interval_sec == 0) {
00677
00678 m_rolling_interval_sec = rolling_interval_sec;
00679 } else {
00680 m_rolling_interval_sec = rolling_interval_sec;
00681
00682 while (Log::MAX_ROLLING_INTERVAL_SEC % ++m_rolling_interval_sec);
00683 }
00684
00685 if (m_rolling_interval_sec != rolling_interval_sec) {
00686 Note("Rolling interval adjusted from %d sec to %d sec for %s",
00687 rolling_interval_sec, m_rolling_interval_sec, m_filename);
00688 }
00689
00690 if (rolling_offset_hr<0 || rolling_offset_hr> 23) {
00691 rolling_offset_hr = 0;
00692 Note("Rolling offset out of bounds for %s, setting it to %d", m_filename, rolling_offset_hr);
00693 }
00694
00695 m_rolling_offset_hr = rolling_offset_hr;
00696 m_rolling_size_mb = 0;
00697
00698 }
00699
00700 if (rolling_enabled == Log::ROLL_ON_SIZE_ONLY ||
00701 rolling_enabled == Log::ROLL_ON_TIME_OR_SIZE || rolling_enabled == Log::ROLL_ON_TIME_AND_SIZE) {
00702 if (rolling_size_mb < 10) {
00703 m_rolling_size_mb = 10;
00704 Note("Rolling size invalid(%d) for %s, setting it to 10 MB", rolling_size_mb, m_filename);
00705 } else {
00706 m_rolling_size_mb = rolling_size_mb;
00707 }
00708 }
00709
00710 m_rolling_enabled = rolling_enabled;
00711 }
00712 }
00713
00714
00715 unsigned
00716 LogObject::roll_files(long time_now)
00717 {
00718 if (!m_rolling_enabled)
00719 return 0;
00720
00721 unsigned num_rolled = 0;
00722 bool roll_on_time = false;
00723 bool roll_on_size = false;
00724
00725 if (!time_now)
00726 time_now = LogUtils::timestamp();
00727
00728 if (m_rolling_enabled != Log::ROLL_ON_SIZE_ONLY) {
00729 if (m_rolling_interval_sec > 0) {
00730
00731
00732
00733
00734
00735
00736
00737
00738 int secs_to_next = LogUtils::seconds_to_next_roll(time_now, m_rolling_offset_hr, m_rolling_interval_sec);
00739
00740
00741
00742
00743
00744
00745
00746 int secs_since_last = (m_last_roll_time < time_now ? time_now - m_last_roll_time : m_last_roll_time - time_now);
00747
00748
00749
00750
00751 const int missed_window = 10;
00752
00753 roll_on_time =
00754 ((secs_to_next == 0 ||
00755 secs_to_next >= m_rolling_interval_sec - missed_window) && secs_since_last > missed_window);
00756 }
00757 }
00758
00759 if (m_rolling_enabled != Log::ROLL_ON_TIME_ONLY) {
00760 if (m_rolling_size_mb) {
00761
00762
00763 roll_on_size = (get_file_size_bytes() > m_rolling_size_mb * LOG_MEGABYTE);
00764 }
00765 }
00766
00767 if ((roll_on_time && should_roll_on_time(m_rolling_enabled)) ||
00768 (roll_on_size && should_roll_on_size(m_rolling_enabled)) ||
00769 (roll_on_time && roll_on_size && m_rolling_enabled == Log::ROLL_ON_TIME_AND_SIZE)) {
00770 num_rolled = _roll_files(m_last_roll_time, time_now ? time_now : LogUtils::timestamp());
00771 }
00772
00773 return num_rolled;
00774 }
00775
00776
00777 unsigned
00778 LogObject::_roll_files(long last_roll_time, long time_now)
00779 {
00780 unsigned num_rolled = 0;
00781
00782 if (m_logFile) {
00783
00784 if (!writes_to_pipe()) {
00785 num_rolled += m_logFile->roll(last_roll_time, time_now);
00786 }
00787 } else {
00788 LogHost *host;
00789 for (host = m_host_list.first(); host; host = m_host_list.next(host)) {
00790 LogFile *orphan_logfile = host->get_orphan_logfile();
00791 if (orphan_logfile) {
00792 num_rolled += orphan_logfile->roll(last_roll_time, time_now);
00793 }
00794 }
00795 }
00796 m_last_roll_time = time_now;
00797 return num_rolled;
00798 }
00799
00800
00801 void
00802 LogObject::check_buffer_expiration(long time_now)
00803 {
00804 LogBuffer *b = (LogBuffer*)FREELIST_POINTER(m_log_buffer);
00805 if (b && time_now > b->expiration_time()) {
00806 force_new_buffer();
00807 }
00808 }
00809
00810
00811
00812
00813 int
00814 LogObject::do_filesystem_checks()
00815 {
00816 if (m_logFile) {
00817 return m_logFile->do_filesystem_checks();
00818 } else {
00819 return m_host_list.do_filesystem_checks();
00820 }
00821 }
00822
00823
00824
00825
00826
00827 const LogFormat * TextLogObject::textfmt = MakeTextLogFormat();
00828
00829 TextLogObject::TextLogObject(const char *name, const char *log_dir,
00830 bool timestamps, const char *header,
00831 Log::RollingEnabledValues rolling_enabled, int flush_threads,
00832 int rolling_interval_sec, int rolling_offset_hr,
00833 int rolling_size_mb)
00834 : LogObject(TextLogObject::textfmt, log_dir, name, LOG_FILE_ASCII, header,
00835 rolling_enabled, flush_threads, rolling_interval_sec,
00836 rolling_offset_hr, rolling_size_mb)
00837 {
00838 if (timestamps) {
00839 this->set_fmt_timestamps();
00840 }
00841 }
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853 int
00854 TextLogObject::write(const char *format, ...)
00855 {
00856 int ret_val;
00857
00858 ink_assert(format != NULL);
00859 va_list ap;
00860 va_start(ap, format);
00861 ret_val = va_write(format, ap);
00862 va_end(ap);
00863
00864 return ret_val;
00865 }
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877 int
00878 TextLogObject::va_write(const char *format, va_list ap)
00879 {
00880 return this->va_log(NULL, format, ap);
00881 }
00882
00883
00884
00885
00886
00887
00888 LogObjectManager::LogObjectManager()
00889 {
00890 _APImutex = new ink_mutex;
00891 ink_mutex_init(_APImutex, "_APImutex");
00892 }
00893
00894 LogObjectManager::~LogObjectManager()
00895 {
00896 for (unsigned i = 0; i < _objects.length(); ++i) {
00897 if (REF_COUNT_OBJ_REFCOUNT_DEC(_objects[i]) == 0) {
00898 delete _objects[i];
00899 }
00900 }
00901
00902 for (unsigned i = 0; i < _APIobjects.length(); ++i) {
00903 if (REF_COUNT_OBJ_REFCOUNT_DEC(_APIobjects[i]) == 0) {
00904 delete _APIobjects[i];
00905 }
00906 }
00907
00908 delete _APImutex;
00909 }
00910
00911 int
00912 LogObjectManager::_manage_object(LogObject * log_object, bool is_api_object, int maxConflicts)
00913 {
00914 if (is_api_object) {
00915 ACQUIRE_API_MUTEX("A LogObjectManager::_manage_object");
00916 }
00917
00918 bool col_client = log_object->is_collation_client();
00919 int retVal = _solve_internal_filename_conflicts(log_object, maxConflicts);
00920
00921 if (retVal == NO_FILENAME_CONFLICTS) {
00922
00923
00924
00925 if (col_client || (retVal = _solve_filename_conflicts(log_object, maxConflicts), retVal == NO_FILENAME_CONFLICTS)) {
00926
00927
00928
00929 if (log_object->do_filesystem_checks() < 0) {
00930 const char *msg = "The log file %s did not pass filesystem checks. " "No output will be produced for this log";
00931 Error(msg, log_object->get_full_filename());
00932 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, msg, log_object->get_full_filename());
00933 retVal = ERROR_DOING_FILESYSTEM_CHECKS;
00934
00935 } else {
00936
00937
00938
00939 REF_COUNT_OBJ_REFCOUNT_INC(log_object);
00940 if (is_api_object) {
00941 _APIobjects.push_back(log_object);
00942 } else {
00943 _objects.push_back(log_object);
00944 }
00945
00946 ink_release_assert(retVal == NO_FILENAME_CONFLICTS);
00947
00948 Debug("log", "LogObjectManager managing object %s (%s) "
00949 "[signature = %" PRIu64 ", address = %p]",
00950 log_object->get_base_filename(),
00951 col_client ? "collation client" :
00952 log_object->get_full_filename(), log_object->get_signature(), log_object);
00953
00954 if (log_object->has_alternate_name()) {
00955 Warning("The full path for the (%s) LogObject %s "
00956 "with signature %" PRIu64 " "
00957 "has been set to %s rather than %s because the latter "
00958 "is being used by another LogObject",
00959 log_object->receives_remote_data()? "remote" : "local",
00960 log_object->get_base_filename(),
00961 log_object->get_signature(), log_object->get_full_filename(), log_object->get_original_filename());
00962 }
00963 }
00964 }
00965 }
00966
00967 if (is_api_object) {
00968 RELEASE_API_MUTEX("R LogObjectManager::_manage_object");
00969 }
00970
00971 return retVal;
00972 }
00973
00974
00975 int
00976 LogObjectManager::_solve_filename_conflicts(LogObject * log_object, int maxConflicts)
00977 {
00978 int retVal = NO_FILENAME_CONFLICTS;
00979
00980 const char *filename = log_object->get_full_filename();
00981
00982 if (access(filename, F_OK)) {
00983 if (errno != ENOENT) {
00984 const char *msg = "Cannot access log file %s: %s";
00985 const char *se = strerror(errno);
00986
00987 Error(msg, filename, se);
00988 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, msg, filename, se);
00989 retVal = ERROR_ACCESSING_LOG_FILE;
00990 }
00991 } else {
00992
00993
00994 uint64_t signature = 0;
00995 MetaInfo meta_info(filename);
00996 bool conflicts = true;
00997
00998 if (meta_info.file_open_successful()) {
00999 bool got_sig = meta_info.get_log_object_signature(&signature);
01000 uint64_t obj_sig = log_object->get_signature();
01001
01002 if (got_sig && signature == obj_sig) {
01003 conflicts = false;
01004 }
01005 Debug("log", "LogObjectManager::_solve_filename_conflicts\n"
01006 "\tfilename = %s\n"
01007 "\tmeta file signature = %" PRIu64 "\n"
01008 "\tlog object signature = %" PRIu64 "\n" "\tconflicts = %d", filename, signature, obj_sig, conflicts);
01009 }
01010
01011 if (conflicts) {
01012 if (maxConflicts == 0) {
01013
01014
01015 const char *msg = "Cannot solve filename conflicts for log file %s";
01016
01017 Error(msg, filename);
01018 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, msg, filename);
01019 retVal = CANNOT_SOLVE_FILENAME_CONFLICTS;
01020 } else {
01021
01022
01023
01024
01025
01026
01027
01028 bool roll_file = true;
01029
01030 if (log_object->writes_to_pipe()) {
01031
01032
01033
01034
01035 struct stat s;
01036 if (stat(filename, &s) < 0) {
01037
01038
01039 const char *msg = "Cannot stat log file %s: %s";
01040 char *se = strerror(errno);
01041
01042 Error(msg, filename, se);
01043 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, msg, filename, se);
01044 retVal = ERROR_DETERMINING_FILE_INFO;
01045 roll_file = false;
01046 } else {
01047 if (s.st_mode == S_IFIFO) {
01048 unlink(filename);
01049 roll_file = false;
01050 }
01051 }
01052 }
01053 if (roll_file) {
01054 Warning("File %s will be rolled because a LogObject with "
01055 "different format is requesting the same " "filename", filename);
01056 LogFile logfile(filename, NULL, LOG_FILE_ASCII, 0);
01057 long time_now = LogUtils::timestamp();
01058
01059 if (logfile.roll(time_now - log_object->get_rolling_interval(), time_now) == 0) {
01060
01061
01062 const char *msg = "Cannot roll log file %s to fix log " "filename conflicts";
01063
01064 Error(msg, filename);
01065 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, msg, filename);
01066 retVal = CANNOT_SOLVE_FILENAME_CONFLICTS;
01067
01068 }
01069 }
01070 }
01071 }
01072 }
01073 return retVal;
01074 }
01075
01076
01077 bool
01078 LogObjectManager::_has_internal_filename_conflict(const char *filename, LogObjectList& objects)
01079 {
01080 for (unsigned i = 0; i < objects.length(); i++) {
01081
01082 if (!objects[i]->is_collation_client()) {
01083
01084
01085
01086
01087 if (strcmp(objects[i]->get_full_filename(), filename) == 0) {
01088 return true;
01089 }
01090 }
01091 }
01092 return false;
01093 }
01094
01095
01096 int
01097 LogObjectManager::_solve_internal_filename_conflicts(LogObject *log_object, int maxConflicts, int fileNum)
01098 {
01099 int retVal = NO_FILENAME_CONFLICTS;
01100 const char *filename = log_object->get_full_filename();
01101
01102 if (_has_internal_filename_conflict(filename, _objects) ||
01103 _has_internal_filename_conflict(filename, _APIobjects)) {
01104 if (fileNum < maxConflicts) {
01105 char new_name[MAXPATHLEN];
01106
01107 snprintf(new_name, sizeof(new_name), "%s%s%d",
01108 log_object->get_original_filename(), LOGFILE_SEPARATOR_STRING, ++fileNum);
01109 log_object->rename(new_name);
01110 retVal = _solve_internal_filename_conflicts(log_object, maxConflicts, fileNum);
01111 } else {
01112 const char *msg = "Cannot solve filename conflicts for log file %s";
01113
01114 Error(msg, filename);
01115 LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR, msg, filename);
01116 retVal = CANNOT_SOLVE_FILENAME_CONFLICTS;
01117 }
01118 }
01119 return retVal;
01120 }
01121
01122
01123 LogObject *
01124 LogObjectManager::get_object_with_signature(uint64_t signature)
01125 {
01126 for (unsigned i = 0; i < this->_objects.length(); i++) {
01127 LogObject * obj = this->_objects[i];
01128
01129 if (obj->get_signature() == signature) {
01130 return obj;
01131 }
01132 }
01133 return NULL;
01134 }
01135
01136
01137 void
01138 LogObjectManager::check_buffer_expiration(long time_now)
01139 {
01140 for (unsigned i = 0; i < this->_objects.length(); i++) {
01141 this->_objects[i]->check_buffer_expiration(time_now);
01142 }
01143
01144 ACQUIRE_API_MUTEX("A LogObjectManager::check_buffer_expiration");
01145
01146 for (unsigned i = 0; i < this->_APIobjects.length(); i++) {
01147 this->_APIobjects[i]->check_buffer_expiration(time_now);
01148 }
01149
01150 RELEASE_API_MUTEX("R LogObjectManager::check_buffer_expiration");
01151 }
01152
01153 size_t
01154 LogObjectManager::preproc_buffers(int idx)
01155 {
01156 size_t buffers_preproced = 0;
01157
01158 for (unsigned i = 0; i < this->_objects.length(); i++) {
01159 buffers_preproced += this->_objects[i]->preproc_buffers(idx);
01160 }
01161
01162 ACQUIRE_API_MUTEX("A LogObjectManager::preproc_buffers");
01163
01164 for (unsigned i = 0; i < this->_APIobjects.length(); i++) {
01165 buffers_preproced += this->_APIobjects[i]->preproc_buffers(idx);
01166 }
01167
01168 RELEASE_API_MUTEX("R LogObjectManager::preproc_buffers");
01169
01170 return buffers_preproced;
01171 }
01172
01173
01174 bool
01175 LogObjectManager::unmanage_api_object(LogObject * logObject)
01176 {
01177 ACQUIRE_API_MUTEX("A LogObjectManager::unmanage_api_object");
01178
01179 if (this->_APIobjects.in(logObject)) {
01180 this->_APIobjects.remove(logObject);
01181
01182
01183 logObject->force_new_buffer();
01184 new_Derefer(logObject, HRTIME_SECONDS(60));
01185
01186 RELEASE_API_MUTEX("R LogObjectManager::unmanage_api_object");
01187 return true;
01188 }
01189
01190 RELEASE_API_MUTEX("R LogObjectManager::unmanage_api_object");
01191 return false;
01192 }
01193
01194
01195 void
01196 LogObjectManager::add_filter_to_all(LogFilter * filter)
01197 {
01198 for (unsigned i = 0; i < this->_objects.length(); i++) {
01199 _objects[i]->add_filter(filter);
01200 }
01201 }
01202
01203
01204 void
01205 LogObjectManager::open_local_pipes()
01206 {
01207
01208
01209
01210 for (unsigned i = 0; i < this->_objects.length(); i++) {
01211 LogObject *obj = _objects[i];
01212 if (obj->writes_to_pipe() && !obj->is_collation_client()) {
01213 obj->m_logFile->open_file();
01214 }
01215 }
01216 }
01217
01218
01219 void
01220 LogObjectManager::transfer_objects(LogObjectManager & old_mgr)
01221 {
01222 unsigned num_kept_objects = 0;
01223
01224 Debug("log-config-transfer", "transferring objects from LogObjectManager %p, to %p", &old_mgr, this);
01225
01226 if (is_debug_tag_set("log-config-transfer")) {
01227 Debug("log-config-transfer", "TRANSFER OBJECTS: list of old objects");
01228 for (unsigned i = 0; i < old_mgr._objects.length(); i++) {
01229 Debug("log-config-transfer", "%s", old_mgr._objects[i]->get_original_filename());
01230 }
01231
01232 Debug("log-config-transfer", "TRANSFER OBJECTS : list of new objects");
01233 for (unsigned i = 0; i < this->_objects.length(); i++) {
01234 Debug("log-config-transfer", "%s", _objects[i]->get_original_filename());
01235 }
01236 }
01237
01238
01239 for (unsigned i = 0; i < old_mgr._APIobjects.length(); ++i) {
01240 manage_api_object(old_mgr._APIobjects[i]);
01241 }
01242
01243 for (unsigned i = 0; i < old_mgr._objects.length(); ++i) {
01244 LogObject * old_obj = old_mgr._objects[i];
01245 LogObject * new_obj;
01246
01247 Debug("log-config-transfer", "examining existing object %s", old_obj->get_base_filename());
01248
01249
01250
01251
01252 for (unsigned j = 0; j < _objects.length(); j++) {
01253 new_obj = _objects[j];
01254
01255 Debug("log-config-transfer",
01256 "comparing existing object %s to new object %s", old_obj->get_base_filename(), new_obj->get_base_filename());
01257
01258 if (*new_obj == *old_obj) {
01259 Debug("log-config-transfer", "keeping existing object %s", old_obj->get_base_filename());
01260
01261 REF_COUNT_OBJ_REFCOUNT_INC(old_obj);
01262 this->_objects[j] = old_obj;
01263
01264 if (REF_COUNT_OBJ_REFCOUNT_DEC(new_obj) == 0) {
01265 delete new_obj;
01266 }
01267 ++num_kept_objects;
01268 break;
01269 }
01270 }
01271 }
01272
01273 if (is_debug_tag_set("log-config-transfer")) {
01274 Debug("log-config-transfer", "Log Object List after transfer:");
01275 display();
01276 }
01277 }
01278
01279 unsigned
01280 LogObjectManager::roll_files(long time_now)
01281 {
01282 int num_rolled = 0;
01283
01284 for (unsigned i = 0; i < this->_objects.length(); i++) {
01285 num_rolled += this->_objects[i]->roll_files(time_now);
01286 }
01287
01288 ACQUIRE_API_MUTEX("A LogObjectManager::roll_files");
01289
01290 for (unsigned i = 0; i < this->_APIobjects.length(); i++) {
01291 num_rolled += this->_APIobjects[i]->roll_files(time_now);
01292 }
01293
01294 RELEASE_API_MUTEX("R LogObjectManager::roll_files");
01295
01296 return num_rolled;
01297 }
01298
01299 void
01300 LogObjectManager::display(FILE * str)
01301 {
01302 for (unsigned i = 0; i < this->_objects.length(); i++) {
01303 _objects[i]->display(str);
01304 }
01305
01306 ACQUIRE_API_MUTEX("A LogObjectManager::display");
01307 for (unsigned i = 0; i < this->_APIobjects.length(); i++) {
01308 _APIobjects[i]->display(str);
01309 }
01310 RELEASE_API_MUTEX("R LogObjectManager::display");
01311 }
01312
01313 LogObject *
01314 LogObjectManager::find_by_format_name(const char *name) const
01315 {
01316 for (unsigned i = 0; i < this->_objects.length(); ++i) {
01317 if (this->_objects[i] && this->_objects[i]->m_format->name_id() == LogFormat::id_from_name(name)) {
01318 return this->_objects[i];
01319 }
01320 }
01321 return NULL;
01322 }
01323
01324 unsigned
01325 LogObjectManager::get_num_collation_clients() const
01326 {
01327 unsigned coll_clients = 0;
01328
01329 for (unsigned i = 0; i < this->_objects.length(); ++i) {
01330 if (this->_objects[i] && this->_objects[i]->is_collation_client()) {
01331 ++coll_clients;
01332 }
01333 }
01334 return coll_clients;
01335 }
01336
01337 int
01338 LogObjectManager::log(LogAccess * lad)
01339 {
01340 int ret = Log::SKIP;
01341 ProxyMutex *mutex = this_thread()->mutex;
01342
01343 for (unsigned i = 0; i < this->_objects.length(); i++) {
01344
01345
01346
01347
01348
01349 if (_objects[i]->m_auto_created)
01350 continue;
01351
01352 ret |= _objects[i]->log(lad);
01353 }
01354
01355
01356
01357
01358
01359
01360 if (unlikely(ret & Log::FAIL)) {
01361 RecIncrRawStat(log_rsb, mutex->thread_holding,
01362 log_stat_event_log_access_fail_stat, 1);
01363 } else if (unlikely(ret & Log::FULL)) {
01364 RecIncrRawStat(log_rsb, mutex->thread_holding,
01365 log_stat_event_log_access_full_stat, 1);
01366 } else if (likely(ret & Log::LOG_OK)) {
01367 RecIncrRawStat(log_rsb, mutex->thread_holding,
01368 log_stat_event_log_access_ok_stat, 1);
01369 } else if (unlikely(ret & Log::AGGR)) {
01370 RecIncrRawStat(log_rsb, mutex->thread_holding,
01371 log_stat_event_log_access_aggr_stat, 1);
01372 } else if (likely(ret & Log::SKIP)) {
01373 RecIncrRawStat(log_rsb, mutex->thread_holding,
01374 log_stat_event_log_access_skip_stat, 1);
01375 } else {
01376 ink_release_assert("Unexpected result");
01377 }
01378
01379 return ret;
01380 }
01381
01382 void
01383 LogObjectManager::flush_all_objects()
01384 {
01385 for (unsigned i = 0; i < this->_objects.length(); ++i) {
01386 this->_objects[i]->force_new_buffer();
01387 }
01388
01389 ACQUIRE_API_MUTEX("A LogObjectManager::flush_all_objects");
01390
01391 for (unsigned i = 0; i < this->_APIobjects.length(); ++i) {
01392 this->_APIobjects[i]->force_new_buffer();
01393 }
01394
01395 RELEASE_API_MUTEX("R LogObjectManager::flush_all_objects");
01396 }
01397
01398 #if TS_HAS_TESTS
01399
01400 static LogObject *
01401 MakeTestLogObject(const char * name)
01402 {
01403 const char * tmpdir = getenv("TMPDIR");
01404 LogFormat format("testfmt", NULL);
01405
01406 if (!tmpdir) {
01407 tmpdir = "/tmp";
01408 }
01409
01410 return new LogObject(&format, tmpdir, name,
01411 LOG_FILE_ASCII , name ,
01412 Log::ROLL_ON_TIME_ONLY , 1 );
01413 }
01414
01415 REGRESSION_TEST(LogObjectManager_Transfer)(RegressionTest * t, int , int * pstatus)
01416 {
01417 TestBox box(t, pstatus);
01418
01419
01420
01421
01422 {
01423 LogObjectManager mgr1;
01424 LogObjectManager mgr2;
01425
01426 mgr1.manage_object(MakeTestLogObject("object1"));
01427 mgr1.manage_object(MakeTestLogObject("object2"));
01428 mgr1.manage_object(MakeTestLogObject("object3"));
01429 mgr1.manage_object(MakeTestLogObject("object4"));
01430
01431 mgr2.transfer_objects(mgr1);
01432
01433 rprintf(t, "mgr1 has %d objects, mgr2 has %d objects\n",
01434 (int)mgr1.get_num_objects(), (int)mgr2.get_num_objects());
01435
01436 rprintf(t, "running Log::periodoc_tasks()\n");
01437 Log::periodic_tasks(ink_get_hrtime() / HRTIME_SECOND);
01438 rprintf(t, "Log::periodoc_tasks() done\n");
01439 }
01440
01441 box = REGRESSION_TEST_PASSED;
01442 }
01443
01444 #endif