blob: 8d9aa47d333f5f75e76ad64870084aaf0c97fa0b [file] [log] [blame]
/** @file
A brief file description
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/***************************************************************************
Log.cc
This file defines the implementation of the static Log class, which is
primarily used as a namespace. That is, there are no Log objects, but the
class scope and static members provide a protected namespace for all of
the logging routines and enumerated types. When C++ namespaces are more
widely-implemented, Log could be implemented as a namespace rather than a
class.
***************************************************************************/
#include "inktomi++.h"
#include "Error.h"
#include "Main.h"
#include "P_EventSystem.h"
#include "P_Net.h"
#include "I_Machine.h"
#include "HTTP.h"
#include "LogAccess.h"
#include "LogField.h"
#include "LogFilter.h"
#include "LogFormat.h"
#include "LogFile.h"
#include "LogHost.h"
#include "LogObject.h"
#include "LogConfig.h"
#include "LogBuffer.h"
#include "LogUtils.h"
#include "Log.h"
#include "LogSock.h"
#include "SimpleTokenizer.h"
#include "ink_apidefs.h"
#define FLUSH_THREAD_SLEEP_TIMEOUT (1)
#define FLUSH_THREAD_MIN_FLUSH_COUNTER (FLUSH_ARRAY_SIZE/4)
// Log global objects
inkcoreapi TextLogObject *
Log::error_log = NULL;
LogConfig *
Log::config = NULL;
LogFieldList
Log::global_field_list;
//LogBufferList Log::global_buffer_full_list;
//LogBufferList Log::global_buffer_delete_list; - vl: not used
LogFormat *
Log::global_scrap_format = NULL;
LogObject *
Log::global_scrap_object = NULL;
Log::LoggingMode Log::logging_mode = LOG_NOTHING;
// Inactive objects
LogObject **
Log::inactive_objects;
size_t
Log::numInactiveObjects;
size_t
Log::maxInactiveObjects;
// Flush thread stuff
volatile unsigned long
Log::flush_counter = 0;
ink_mutex
Log::flush_mutex;
ink_cond
Log::flush_cond;
ink_thread
Log::flush_thread;
// Collate thread stuff
ink_mutex
Log::collate_mutex;
ink_cond
Log::collate_cond;
ink_thread
Log::collate_thread;
int
Log::collation_accept_file_descriptor;
int
Log::collation_port;
// Log private objects
int
Log::init_status = 0;
int
Log::config_flags = 0;
bool
Log::logging_mode_changed = false;
// Hash table for LogField symbols
InkHashTable *
Log::field_symbol_hash = 0;
RecRawStatBlock *
log_rsb;
/*-------------------------------------------------------------------------
Log::change_configuration
This routine is invoked when the current LogConfig object says it needs
to be changed (as the result of a manager callback).
-------------------------------------------------------------------------*/
void
Log::change_configuration()
{
Debug("log2-config", "Changing configuration ...");
LogConfig *new_config = NEW(new LogConfig);
ink_assert(new_config != NULL);
new_config->read_configuration_variables();
// grab the _APImutex so we can transfer the api objects to
// the new config
//
ink_mutex_acquire(Log::config->log_object_manager._APImutex);
Debug("log2-api-mutex", "Log::change_configuration acquired api mutex");
new_config->init(Log::config);
// Swap in the new config object
//
ink_atomic_swap_ptr((void *) &Log::config, new_config);
// Force new buffers for inactive objects
//
for (size_t i = 0; i < numInactiveObjects; i++) {
inactive_objects[i]->force_new_buffer();
}
ink_mutex_release(Log::config->log_object_manager._APImutex);
Debug("log2-api-mutex", "Log::change_configuration released api mutex");
Debug("log2-config", "... new configuration in place");
}
void
Log::add_to_inactive(LogObject * object)
{
if (Log::numInactiveObjects == Log::maxInactiveObjects) {
Log::maxInactiveObjects += LOG_OBJECT_ARRAY_DELTA;
LogObject **new_objects = new LogObject *[Log::maxInactiveObjects];
for (size_t i = 0; i < Log::numInactiveObjects; i++) {
new_objects[i] = Log::inactive_objects[i];
}
delete[]Log::inactive_objects;
Log::inactive_objects = new_objects;
}
Log::inactive_objects[Log::numInactiveObjects++] = object;
}
/*-------------------------------------------------------------------------
PERIODIC EVENTS
There are a number of things that need to get done on a periodic basis,
such as checking the amount of space used, seeing if it's time to roll
files, and flushing idle log buffers. Most of these tasks require having
exclusive access to the back-end structures, which is controlled by the
flush_thread. Therefore, we will simply instruct the flush thread to
execute a periodic_tasks() function once per period. To ensure that the
tasks are executed AT LEAST once each period, we'll register a call-back
with the system and trigger the flush thread's condition variable. To
ensure that the tasks are executed AT MOST once per period, the flush
thread will keep track of executions per period.
-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------
PeriodicWakeup
This continuation is invoked each second to wake-up the flush thread,
just in case it's sleeping on the job.
-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------
Log::periodic_tasks
This function contains all of the tasks that need to be done each
second.
-------------------------------------------------------------------------*/
void
Log::periodic_tasks(long time_now)
{
// delete inactive objects
//
// we don't care if we miss an object that may be added to the set of
// inactive objects just after we have read numInactiveObjects and found
// it to be zero; we will get a chance to delete it next time
//
Debug("log2-api-mutex", "entering Log::periodic_tasks");
if (numInactiveObjects) {
ink_mutex_acquire(Log::config->log_object_manager._APImutex);
Debug("log2-api-mutex", "Log::periodic_tasks acquired api mutex");
Debug("log2-periodic", "Deleting inactive_objects");
for (size_t i = 0; i < numInactiveObjects; i++) {
delete inactive_objects[i];
}
numInactiveObjects = 0;
ink_mutex_release(Log::config->log_object_manager._APImutex);
Debug("log2-api-mutex", "Log::periodic_tasks released api mutex");
}
if (logging_mode_changed || Log::config->reconfiguration_needed) {
Debug("log2-config", "Performing reconfiguration, init status = %d", init_status);
if (logging_mode_changed) {
int val = (int) LOG_ConfigReadInteger("proxy.config.log2.logging_enabled");
if (val<LOG_NOTHING || val> FULL_LOGGING) {
logging_mode = FULL_LOGGING;
Warning("proxy.config.log2.logging_enabled has an invalid " "value setting it to %d", logging_mode);
} else {
logging_mode = (LoggingMode) val;
}
logging_mode_changed = false;
}
// even if we are disabling logging, we call change configuration
// so that log objects are flushed
//
change_configuration();
} else if (logging_mode > LOG_NOTHING ||
config->collation_mode == LogConfig::COLLATION_HOST || config->has_api_objects()) {
Debug("log2-periodic", "Performing periodic tasks");
// Check if space is ok and update the space used
//
if (config->space_is_short() || time_now % config->space_used_frequency == 0) {
Log::config->update_space_used();
}
// See if there are any buffers that have expired
//
Log::config->log_object_manager.check_buffer_expiration(time_now);
if (error_log) {
error_log->check_buffer_expiration(time_now);
}
// Check if we received a request to roll, and roll if so, otherwise
// give objects a chance to roll if they need to
//
int num_rolled = 0;
if (Log::config->roll_log_files_now) {
if (error_log) {
num_rolled += error_log->roll_files(time_now);
}
if (global_scrap_object) {
num_rolled += global_scrap_object->roll_files(time_now);
}
num_rolled += Log::config->log_object_manager.roll_files(time_now);
Log::config->roll_log_files_now = FALSE;
} else {
if (error_log) {
num_rolled += error_log->roll_files_if_needed(time_now);
}
if (global_scrap_object) {
num_rolled += global_scrap_object->roll_files_if_needed(time_now);
}
num_rolled += Log::config->log_object_manager.roll_files_if_needed(time_now);
}
}
}
/*-------------------------------------------------------------------------
MAIN INTERFACE
-------------------------------------------------------------------------*/
struct LoggingFlushContinuation:Continuation
{
int mainEvent(int event, void *data)
{
Log::flush_thread_main(NULL);
return 0;
}
LoggingFlushContinuation():Continuation(NULL)
{
SET_HANDLER(&LoggingFlushContinuation::mainEvent);
}
};
struct LoggingCollateContinuation:Continuation
{
int mainEvent(int event, void *data)
{
Log::collate_thread_main(NULL);
return 0;
}
LoggingCollateContinuation():Continuation(NULL)
{
SET_HANDLER(&LoggingCollateContinuation::mainEvent);
}
};
/*-------------------------------------------------------------------------
Log::init_fields
Define the available logging fields.
This used to be part of the init() function, but now is separate so that
standalone programs that do not require more services (e.g., that do not
need to read records.config) can just call init_fields.
Note that the LogFields are added to the list with the copy flag false so
that the LogFieldList destructor will reclaim this memory.
-------------------------------------------------------------------------*/
void
Log::init_fields()
{
if (init_status & FIELDS_INITIALIZED)
return;
LogField *field;
//
// Create a hash table that will be used to find the global field
// objects from their symbol names in a rapid manner.
//
field_symbol_hash = ink_hash_table_create(InkHashTableKeyType_String);
// client -> proxy fields
Ptr<LogFieldAliasIP> ip_map = NEW(new LogFieldAliasIP);
field = NEW(new LogField("client_host_ip", "chi",
LogField::sINT,
&LogAccess::marshal_client_host_ip,
&LogAccess::unmarshal_ip, (Ptr<LogFieldAliasMap>) ip_map));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "chi", field);
Ptr<LogFieldAliasIPhex> ip_map_hex = NEW(new LogFieldAliasIPhex);
field = NEW(new LogField("client_host_ip_hex", "chih",
LogField::sINT,
&LogAccess::marshal_client_host_ip,
&LogAccess::unmarshal_ip, (Ptr<LogFieldAliasMap>) ip_map_hex));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "chih", field);
// Jira TS-40: Re-add Squid field 'caun'
field = NEW (new LogField ("client_auth_user_name", "caun",
LogField::STRING,
&LogAccess::marshal_client_auth_user_name,
&LogAccess::unmarshal_str));
global_field_list.add (field, false);
ink_hash_table_insert (field_symbol_hash, "caun", field);
field = NEW(new LogField("client_req_timestamp_sec", "cqts",
LogField::sINT,
&LogAccess::marshal_client_req_timestamp_sec, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqts", field);
field = NEW(new LogField("client_req_timestamp_hex_sec", "cqth",
LogField::sINT,
&LogAccess::marshal_client_req_timestamp_sec, &LogAccess::unmarshal_int_to_str_hex));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqth", field);
field = NEW(new LogField("client_req_timestamp_squid", "cqtq",
LogField::sINT,
&LogAccess::marshal_client_req_timestamp_sec, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqtq", field);
field = NEW(new LogField("client_req_timestamp_netscape", "cqtn",
LogField::sINT,
&LogAccess::marshal_client_req_timestamp_sec, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqtn", field);
field = NEW(new LogField("client_req_timestamp_date", "cqtd",
LogField::sINT,
&LogAccess::marshal_client_req_timestamp_sec, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqtd", field);
field = NEW(new LogField("client_req_timestamp_time", "cqtt",
LogField::sINT,
&LogAccess::marshal_client_req_timestamp_sec, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqtt", field);
field = NEW(new LogField("client_req_text", "cqtx",
LogField::STRING, &LogAccess::marshal_client_req_text, &LogAccess::unmarshal_http_text));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqtx", field);
field = NEW(new LogField("client_req_http_method", "cqhm",
LogField::STRING, &LogAccess::marshal_client_req_http_method, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqhm", field);
field = NEW(new LogField("client_req_url", "cqu",
LogField::STRING, &LogAccess::marshal_client_req_url, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqu", field);
field = NEW(new LogField("client_req_url_canonical", "cquc",
LogField::STRING, &LogAccess::marshal_client_req_url_canon, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cquc", field);
field = NEW(new LogField("client_req_unmapped_url_canonical", "cquuc",
LogField::STRING,
&LogAccess::marshal_client_req_unmapped_url_canon, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cquuc", field);
field = NEW(new LogField("client_req_unmapped_url_path", "cquup",
LogField::STRING,
&LogAccess::marshal_client_req_unmapped_url_path, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cquup", field);
field = NEW(new LogField("client_req_url_scheme", "cqus",
LogField::STRING, &LogAccess::marshal_client_req_url_scheme, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqus", field);
field = NEW(new LogField("client_req_url_path", "cqup",
LogField::STRING, &LogAccess::marshal_client_req_url_path, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqup", field);
field = NEW(new LogField("client_req_http_version", "cqhv",
LogField::dINT,
&LogAccess::marshal_client_req_http_version, &LogAccess::unmarshal_http_version));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqhv", field);
field = NEW(new LogField("client_req_header_len", "cqhl",
LogField::sINT,
&LogAccess::marshal_client_req_header_len, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqhl", field);
field = NEW(new LogField("client_req_body_len", "cqbl",
LogField::sINT, &LogAccess::marshal_client_req_body_len, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cqbl", field);
Ptr<LogFieldAliasTable> finish_status_map = NEW(new LogFieldAliasTable);
finish_status_map->init(N_LOG_FINISH_CODE_TYPES,
LOG_FINISH_FIN, "FIN", LOG_FINISH_INTR, "INTR", LOG_FINISH_TIMEOUT, "TIMEOUT");
field = NEW(new LogField("client_finish_status_code", "cfsc",
LogField::sINT,
&LogAccess::marshal_client_finish_status_code,
&LogAccess::unmarshal_finish_status, (Ptr<LogFieldAliasMap>) finish_status_map));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cfsc", field);
field = NEW(new LogField("client_gid", "cgid",
LogField::STRING, &LogAccess::marshal_client_gid, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cgid", field);
// proxy -> client fields
field = NEW(new LogField("proxy_resp_content_type", "psct",
LogField::STRING, &LogAccess::marshal_proxy_resp_content_type, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "psct", field);
field = NEW(new LogField("proxy_resp_squid_len", "psql",
LogField::sINT, &LogAccess::marshal_proxy_resp_squid_len, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "psql", field);
field = NEW(new LogField("proxy_resp_content_len", "pscl",
LogField::sINT,
&LogAccess::marshal_proxy_resp_content_len, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "pscl", field);
field = NEW(new LogField("proxy_resp_content_len_hex", "psch",
LogField::sINT,
&LogAccess::marshal_proxy_resp_content_len, &LogAccess::unmarshal_int_to_str_hex));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "psch", field);
field = NEW(new LogField("proxy_resp_status_code", "pssc",
LogField::sINT,
&LogAccess::marshal_proxy_resp_status_code, &LogAccess::unmarshal_http_status));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "pssc", field);
field = NEW(new LogField("proxy_resp_header_len", "pshl",
LogField::sINT,
&LogAccess::marshal_proxy_resp_header_len, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "pshl", field);
field = NEW(new LogField("proxy_finish_status_code", "pfsc",
LogField::sINT,
&LogAccess::marshal_proxy_finish_status_code,
&LogAccess::unmarshal_finish_status, (Ptr<LogFieldAliasMap>) finish_status_map));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "pfsc", field);
Ptr<LogFieldAliasTable> cache_code_map = NEW(new LogFieldAliasTable);
cache_code_map->
init(62,
SQUID_LOG_EMPTY, "UNDEFINED",
SQUID_LOG_TCP_HIT, "TCP_HIT",
SQUID_LOG_TCP_DISK_HIT, "TCP_DISK_HIT",
SQUID_LOG_TCP_MEM_HIT, "TCP_MEM_HIT",
SQUID_LOG_TCP_MISS, "TCP_MISS",
SQUID_LOG_TCP_EXPIRED_MISS, "TCP_EXPIRED_MISS",
SQUID_LOG_TCP_REFRESH_HIT, "TCP_REFRESH_HIT",
SQUID_LOG_TCP_REF_FAIL_HIT, "TCP_REF_FAIL_HIT",
SQUID_LOG_TCP_REFRESH_MISS, "TCP_REFRESH_MISS",
SQUID_LOG_TCP_CLIENT_REFRESH, "TCP_CLIENT_REFRESH",
SQUID_LOG_TCP_IMS_HIT, "TCP_IMS_HIT",
SQUID_LOG_TCP_IMS_MISS, "TCP_IMS_MISS",
SQUID_LOG_TCP_SWAPFAIL, "TCP_SWAPFAIL",
SQUID_LOG_TCP_DENIED, "TCP_DENIED",
SQUID_LOG_TCP_WEBFETCH_MISS, "TCP_WEBFETCH_MISS",
SQUID_LOG_TCP_SPIDER_BYPASS, "TCP_SPIDER_BYPASS",
SQUID_LOG_TCP_FUTURE_2, "TCP_FUTURE_2",
SQUID_LOG_TCP_HIT_REDIRECT, "TCP_HIT_REDIRECT",
SQUID_LOG_TCP_MISS_REDIRECT, "TCP_MISS_REDIRECT",
SQUID_LOG_TCP_HIT_X_REDIRECT, "TCP_HIT_X_REDIRECT",
SQUID_LOG_TCP_MISS_X_REDIRECT, "TCP_MISS_X_REDIRECT",
SQUID_LOG_UDP_HIT, "UDP_HIT",
SQUID_LOG_UDP_WEAK_HIT, "UDP_WEAK_HIT",
SQUID_LOG_UDP_HIT_OBJ, "UDP_HIT_OBJ",
SQUID_LOG_UDP_MISS, "UDP_MISS",
SQUID_LOG_UDP_DENIED, "UDP_DENIED",
SQUID_LOG_UDP_INVALID, "UDP_INVALID",
SQUID_LOG_UDP_RELOADING, "UDP_RELOADING",
SQUID_LOG_UDP_FUTURE_1, "UDP_FUTURE_1",
SQUID_LOG_UDP_FUTURE_2, "UDP_FUTURE_2",
SQUID_LOG_ERR_READ_TIMEOUT, "ERR_READ_TIMEOUT",
SQUID_LOG_ERR_LIFETIME_EXP, "ERR_LIFETIME_EXP",
SQUID_LOG_ERR_NO_CLIENTS_BIG_OBJ, "ERR_NO_CLIENTS_BIG_OBJ",
SQUID_LOG_ERR_READ_ERROR, "ERR_READ_ERROR",
SQUID_LOG_ERR_CLIENT_ABORT, "ERR_CLIENT_ABORT",
SQUID_LOG_ERR_CONNECT_FAIL, "ERR_CONNECT_FAIL",
SQUID_LOG_ERR_INVALID_REQ, "ERR_INVALID_REQ",
SQUID_LOG_ERR_UNSUP_REQ, "ERR_UNSUP_REQ",
SQUID_LOG_ERR_INVALID_URL, "ERR_INVALID_URL",
SQUID_LOG_ERR_NO_FDS, "ERR_NO_FDS",
SQUID_LOG_ERR_DNS_FAIL, "ERR_DNS_FAIL",
SQUID_LOG_ERR_NOT_IMPLEMENTED, "ERR_NOT_IMPLEMENTED",
SQUID_LOG_ERR_CANNOT_FETCH, "ERR_CANNOT_FETCH",
SQUID_LOG_ERR_NO_RELAY, "ERR_NO_RELAY",
SQUID_LOG_ERR_DISK_IO, "ERR_DISK_IO",
SQUID_LOG_ERR_ZERO_SIZE_OBJECT, "ERR_ZERO_SIZE_OBJECT",
SQUID_LOG_ERR_PROXY_DENIED, "ERR_PROXY_DENIED",
SQUID_LOG_ERR_WEBFETCH_DETECTED, "ERR_WEBFETCH_DETECTED",
SQUID_LOG_ERR_FUTURE_1, "ERR_FUTURE_1",
SQUID_LOG_ERR_SPIDER_MEMBER_ABORTED, "ERR_SPIDER_MEMBER_ABORTED",
SQUID_LOG_ERR_SPIDER_PARENTAL_CONTROL_RESTRICTION, "ERR_SPIDER_PARENTAL_CONTROL_RESTRICTION",
SQUID_LOG_ERR_SPIDER_UNSUPPORTED_HTTP_VERSION, "ERR_SPIDER_UNSUPPORTED_HTTP_VERSION",
SQUID_LOG_ERR_SPIDER_UIF, "ERR_SPIDER_UIF",
SQUID_LOG_ERR_SPIDER_FUTURE_USE_1, "ERR_SPIDER_FUTURE_USE_1",
SQUID_LOG_ERR_SPIDER_TIMEOUT_WHILE_PASSING, "ERR_SPIDER_TIMEOUT_WHILE_PASSING",
SQUID_LOG_ERR_SPIDER_TIMEOUT_WHILE_DRAINING, "ERR_SPIDER_TIMEOUT_WHILE_DRAINING",
SQUID_LOG_ERR_SPIDER_GENERAL_TIMEOUT, "ERR_SPIDER_GENERAL_TIMEOUT",
SQUID_LOG_ERR_SPIDER_CONNECT_FAILED, "ERR_SPIDER_CONNECT_FAILED",
SQUID_LOG_ERR_SPIDER_FUTURE_USE_2, "ERR_SPIDER_FUTURE_USE_2",
SQUID_LOG_ERR_SPIDER_NO_RESOURCES, "ERR_SPIDER_NO_RESOURCES",
SQUID_LOG_ERR_SPIDER_INTERNAL_ERROR, "ERR_SPIDER_INTERNAL_ERROR",
SQUID_LOG_ERR_SPIDER_INTERNAL_IO_ERROR, "ERR_SPIDER_INTERNAL_IO_ERROR",
SQUID_LOG_ERR_SPIDER_DNS_TEMP_ERROR, "ERR_SPIDER_DNS_TEMP_ERROR",
SQUID_LOG_ERR_SPIDER_DNS_HOST_NOT_FOUND, "ERR_SPIDER_DNS_HOST_NOT_FOUND",
SQUID_LOG_ERR_SPIDER_DNS_NO_ADDRESS, "ERR_SPIDER_DNS_NO_ADDRESS", SQUID_LOG_ERR_UNKNOWN, "ERR_UNKNOWN");
field = NEW(new LogField("cache_result_code", "crc",
LogField::sINT,
&LogAccess::marshal_cache_result_code,
&LogAccess::unmarshal_cache_code, (Ptr<LogFieldAliasMap>) cache_code_map));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "crc", field);
field = NEW(new LogField("proxy_resp_origin_bytes", "prob",
LogField::sINT,
&LogAccess::marshal_proxy_resp_origin_bytes, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "prob", field);
field = NEW(new LogField("proxy_resp_cache_bytes", "prcb",
LogField::sINT,
&LogAccess::marshal_proxy_resp_cache_bytes, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "prcb", field);
// proxy -> server fields
field = NEW(new LogField("proxy_req_header_len", "pqhl",
LogField::sINT, &LogAccess::marshal_proxy_req_header_len, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "pqhl", field);
field = NEW(new LogField("proxy_req_body_len", "pqbl",
LogField::sINT, &LogAccess::marshal_proxy_req_body_len, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "pqbl", field);
field = NEW(new LogField("proxy_req_server_name", "pqsn",
LogField::STRING, &LogAccess::marshal_proxy_req_server_name, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "pqsn", field);
field = NEW(new LogField("proxy_req_server_ip", "pqsi",
LogField::sINT,
&LogAccess::marshal_proxy_req_server_ip,
&LogAccess::unmarshal_ip, (Ptr<LogFieldAliasMap>) ip_map));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "pqsi", field);
Ptr<LogFieldAliasTable> hierarchy_map = NEW(new LogFieldAliasTable);
hierarchy_map->
init(36,
SQUID_HIER_EMPTY, "EMPTY",
SQUID_HIER_NONE, "NONE",
SQUID_HIER_DIRECT, "DIRECT",
SQUID_HIER_SIBLING_HIT, "SIBLING_HIT",
SQUID_HIER_PARENT_HIT, "PARENT_HIT",
SQUID_HIER_DEFAULT_PARENT, "DEFAULT_PARENT",
SQUID_HIER_SINGLE_PARENT, "SINGLE_PARENT",
SQUID_HIER_FIRST_UP_PARENT, "FIRST_UP_PARENT",
SQUID_HIER_NO_PARENT_DIRECT, "NO_PARENT_DIRECT",
SQUID_HIER_FIRST_PARENT_MISS, "FIRST_PARENT_MISS",
SQUID_HIER_LOCAL_IP_DIRECT, "LOCAL_IP_DIRECT",
SQUID_HIER_FIREWALL_IP_DIRECT, "FIREWALL_IP_DIRECT",
SQUID_HIER_NO_DIRECT_FAIL, "NO_DIRECT_FAIL",
SQUID_HIER_SOURCE_FASTEST, "SOURCE_FASTEST",
SQUID_HIER_SIBLING_UDP_HIT_OBJ, "SIBLING_UDP_HIT_OBJ",
SQUID_HIER_PARENT_UDP_HIT_OBJ, "PARENT_UDP_HIT_OBJ",
SQUID_HIER_PASSTHROUGH_PARENT, "PASSTHROUGH_PARENT",
SQUID_HIER_SSL_PARENT_MISS, "SSL_PARENT_MISS",
SQUID_HIER_INVALID_CODE, "INVALID_CODE",
SQUID_HIER_TIMEOUT_DIRECT, "TIMEOUT_DIRECT",
SQUID_HIER_TIMEOUT_SIBLING_HIT, "TIMEOUT_SIBLING_HIT",
SQUID_HIER_TIMEOUT_PARENT_HIT, "TIMEOUT_PARENT_HIT",
SQUID_HIER_TIMEOUT_DEFAULT_PARENT, "TIMEOUT_DEFAULT_PARENT",
SQUID_HIER_TIMEOUT_SINGLE_PARENT, "TIMEOUT_SINGLE_PARENT",
SQUID_HIER_TIMEOUT_FIRST_UP_PARENT, "TIMEOUT_FIRST_UP_PARENT",
SQUID_HIER_TIMEOUT_NO_PARENT_DIRECT, "TIMEOUT_NO_PARENT_DIRECT",
SQUID_HIER_TIMEOUT_FIRST_PARENT_MISS, "TIMEOUT_FIRST_PARENT_MISS",
SQUID_HIER_TIMEOUT_LOCAL_IP_DIRECT, "TIMEOUT_LOCAL_IP_DIRECT",
SQUID_HIER_TIMEOUT_FIREWALL_IP_DIRECT, "TIMEOUT_FIREWALL_IP_DIRECT",
SQUID_HIER_TIMEOUT_NO_DIRECT_FAIL, "TIMEOUT_NO_DIRECT_FAIL",
SQUID_HIER_TIMEOUT_SOURCE_FASTEST, "TIMEOUT_SOURCE_FASTEST",
SQUID_HIER_TIMEOUT_SIBLING_UDP_HIT_OBJ, "TIMEOUT_SIBLING_UDP_HIT_OBJ",
SQUID_HIER_TIMEOUT_PARENT_UDP_HIT_OBJ, "TIMEOUT_PARENT_UDP_HIT_OBJ",
SQUID_HIER_TIMEOUT_PASSTHROUGH_PARENT, "TIMEOUT_PASSTHROUGH_PARENT",
SQUID_HIER_TIMEOUT_TIMEOUT_SSL_PARENT_MISS, "TIMEOUT_TIMEOUT_SSL_PARENT_MISS",
SQUID_HIER_INVALID_ASSIGNED_CODE, "INVALID_ASSIGNED_CODE");
field = NEW(new LogField("proxy_hierarchy_route", "phr",
LogField::sINT,
&LogAccess::marshal_proxy_hierarchy_route,
&LogAccess::unmarshal_hierarchy, (Ptr<LogFieldAliasMap>) hierarchy_map));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "phr", field);
field = NEW(new LogField("proxy_host_name", "phn",
LogField::STRING, &LogAccess::marshal_proxy_host_name, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "phn", field);
field = NEW(new LogField("proxy_host_ip", "phi",
LogField::STRING, &LogAccess::marshal_proxy_host_ip, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "phi", field);
// X-WAID
field = NEW(new LogField("accelerator_id", "xid",
LogField::STRING, &LogAccess::marshal_client_accelerator_id, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "xid", field);
// X-WAID
// server -> proxy fields
field = NEW(new LogField("server_host_ip", "shi",
LogField::sINT,
&LogAccess::marshal_server_host_ip,
&LogAccess::unmarshal_ip, (Ptr<LogFieldAliasMap>) ip_map));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "shi", field);
field = NEW(new LogField("server_host_name", "shn",
LogField::STRING, &LogAccess::marshal_server_host_name, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "shn", field);
field = NEW(new LogField("server_resp_status_code", "sssc",
LogField::sINT,
&LogAccess::marshal_server_resp_status_code, &LogAccess::unmarshal_http_status));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "sssc", field);
field = NEW(new LogField("server_resp_content_len", "sscl",
LogField::sINT,
&LogAccess::marshal_server_resp_content_len, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "sscl", field);
field = NEW(new LogField("server_resp_header_len", "sshl",
LogField::sINT,
&LogAccess::marshal_server_resp_header_len, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "sshl", field);
field = NEW(new LogField("server_resp_http_version", "sshv",
LogField::dINT,
&LogAccess::marshal_server_resp_http_version, &LogAccess::unmarshal_http_version));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "sshv", field);
field = NEW(new LogField("client_retry_after_time", "crat",
LogField::sINT,
&LogAccess::marshal_client_retry_after_time, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "crat", field);
// cache write fields
Ptr<LogFieldAliasTable> cache_write_code_map = NEW(new LogFieldAliasTable);
cache_write_code_map->init(N_LOG_CACHE_WRITE_TYPES,
LOG_CACHE_WRITE_NONE, "-",
LOG_CACHE_WRITE_LOCK_MISSED, "WL_MISS",
LOG_CACHE_WRITE_LOCK_ABORTED, "INTR",
LOG_CACHE_WRITE_ERROR, "ERR", LOG_CACHE_WRITE_COMPLETE, "FIN");
field = NEW(new LogField("cache_write_result", "cwr",
LogField::sINT,
&LogAccess::marshal_cache_write_code,
&LogAccess::unmarshal_cache_write_code, (Ptr<LogFieldAliasMap>) cache_write_code_map));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cwr", field);
field = NEW(new LogField("cache_write_transform_result", "cwtr",
LogField::sINT,
&LogAccess::marshal_cache_write_transform_code,
&LogAccess::unmarshal_cache_write_code, (Ptr<LogFieldAliasMap>) cache_write_code_map));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "cwtr", field);
// other fields
field = NEW(new LogField("transfer_time_ms", "ttms",
LogField::sINT, &LogAccess::marshal_transfer_time_ms, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "ttms", field);
field = NEW(new LogField("transfer_time_ms_hex", "ttmh",
LogField::sINT, &LogAccess::marshal_transfer_time_ms, &LogAccess::unmarshal_int_to_str_hex));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "ttmh", field);
field = NEW(new LogField("transfer_time_ms_fractional", "ttmsf",
LogField::sINT, &LogAccess::marshal_transfer_time_ms, &LogAccess::unmarshal_ttmsf));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "ttmsf", field);
field = NEW(new LogField("transfer_time_sec", "tts",
LogField::sINT, &LogAccess::marshal_transfer_time_s, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "tts", field);
field = NEW(new LogField("bandwidth", "band",
LogField::sINT, &LogAccess::marshal_bandwidth, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "band", field);
field = NEW(new LogField("file_size", "fsiz",
LogField::sINT, &LogAccess::marshal_file_size, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "fsiz", field);
Ptr<LogFieldAliasTable> entry_type_map = NEW(new LogFieldAliasTable);
entry_type_map->init(N_LOG_ENTRY_TYPES,
LOG_ENTRY_HTTP, "LOG_ENTRY_HTTP",
LOG_ENTRY_ICP, "LOG_ENTRY_ICP", LOG_ENTRY_MIXT, "LOG_ENTRY_MIXT");
field = NEW(new LogField("log_entry_type", "etype",
LogField::sINT,
&LogAccess::marshal_entry_type,
&LogAccess::unmarshal_entry_type, (Ptr<LogFieldAliasMap>) entry_type_map));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "etype", field);
field = NEW(new LogField("time_to_first_client_byte_ms", "tfcb",
LogField::sINT,
&LogAccess::marshal_time_to_first_client_byte_ms, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "tfcb", field);
field = NEW(new LogField("stream_type", "styp",
LogField::STRING, &LogAccess::marshal_stream_type, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "styp", field);
// MIXT SDK Begin
field = NEW(new LogField("external_plugin_transaction_id", "eptid",
LogField::sINT,
&LogAccess::marshal_external_plugin_transaction_id, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "eptid", field);
// MIXT SDK End
// MIXT SDK_VER_2
field = NEW(new LogField("external_plugin_string", "eps",
LogField::STRING, &LogAccess::marshal_external_plugin_string, &LogAccess::unmarshal_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "eps", field);
// MIXT SDK_VER_2
field = NEW(new LogField("stream_duration_ms", "sdurms",
LogField::sINT, &LogAccess::marshal_stream_duration_ms, &LogAccess::unmarshal_int_to_str));
global_field_list.add(field, false);
ink_hash_table_insert(field_symbol_hash, "sdurms", field);
#define ADD_LOG_FIELD(name, symbol, type, marshal, unmarshal) \
field = NEW (new LogField(name, symbol, type, marshal, unmarshal)); \
global_field_list.add(field, false); \
ink_hash_table_insert(field_symbol_hash, symbol, field)
// This field is for the client DNS name.
// For some protocols (such as WMT), the client itself sends the DNS
// name to the server in a logging message. This field logs that.
// It's probably expensive to do DNS lookups, so this field should normally
// be blank unless the protocol allows an inexpensive way to determine
// the client DNS name.
//
// For WMT, this is equivalent to c-dns
//
ADD_LOG_FIELD("client_dns_name", "cdns", LogField::STRING,
&LogAccess::marshal_client_dns_name, &LogAccess::unmarshal_str);
// This field is for the client operating system name.
//
// For WMT, this is equivalent to c-os
//
ADD_LOG_FIELD("client_dns_name", "cos", LogField::STRING, &LogAccess::marshal_client_os, &LogAccess::unmarshal_str);
// This field is for the client operating system version.
//
// For WMT, this is equivalent to c-osversion
//
ADD_LOG_FIELD("client_os_version", "cosv", LogField::STRING,
&LogAccess::marshal_client_os_version, &LogAccess::unmarshal_str);
// This field is for the client CPU type.
//
// For WMT, this is equivalent to c-cpu
//
ADD_LOG_FIELD("client_cpu", "ccpu", LogField::STRING, &LogAccess::marshal_client_cpu, &LogAccess::unmarshal_str);
// This field is for the client player version.
//
// For WMT, this is equivalent to c-playerversion
//
ADD_LOG_FIELD("client_player_version", "cplyv", LogField::STRING,
&LogAccess::marshal_client_player_version, &LogAccess::unmarshal_str);
// This field is for the client player lanaguage.
//
// For WMT, this is equivalent to c-playerlanguage.
//
ADD_LOG_FIELD("client_player_language", "clang", LogField::STRING,
&LogAccess::marshal_client_player_language, &LogAccess::unmarshal_str);
// This field is for the client user agent.
//
// For WMT, this is equivalent to c(User-Agent)
//
ADD_LOG_FIELD("client_user_agent", "cua", LogField::STRING,
&LogAccess::marshal_client_user_agent, &LogAccess::unmarshal_str);
// This field is for the URL of the referrer.
//
// For WMT, this is equivalent to c(Referer)
//
ADD_LOG_FIELD("referer_url", "rfurl", LogField::STRING, &LogAccess::marshal_referer_url, &LogAccess::unmarshal_str);
// This field is for the audio codec used by the player.
//
// For WMT, this is equivalent to audiocodec
//
ADD_LOG_FIELD("audio_codec", "audcdc", LogField::STRING, &LogAccess::marshal_audio_codec, &LogAccess::unmarshal_str);
// This field is for the video codec used by the player.
//
// For WMT, this is equivalent to videocodec
//
ADD_LOG_FIELD("video_codec", "vidcdc", LogField::STRING, &LogAccess::marshal_video_codec, &LogAccess::unmarshal_str);
// This field is for the number of bytes received by the client
// as reported by the client.
//
// For WMT, this is equivalent to c-bytes
//
ADD_LOG_FIELD("client_bytes_received", "cbytr", LogField::sINT,
&LogAccess::marshal_client_bytes_received, &LogAccess::unmarshal_int_to_str);
// This field is for the number of packets received by the client
// as reported by the client.
//
// For WMT, this is equivalent to c-pkts-received
//
ADD_LOG_FIELD("client_pkts_received", "cpktr", LogField::sINT,
&LogAccess::marshal_client_pkts_received, &LogAccess::unmarshal_int_to_str);
// This field is for the number of lost packets during transmission
// from server to client as reported by the client.
//
// For WMT, this is equivalent to c-pkts-lost-client
//
ADD_LOG_FIELD("client_lost_pkts", "cpktl", LogField::sINT,
&LogAccess::marshal_client_lost_pkts, &LogAccess::unmarshal_int_to_str);
// This field is for the number of lost packets in the network layer
// as reported by the client.
//
// For WMT, this is equivalent to c-pkts-lost-net
//
ADD_LOG_FIELD("client_lost_net_pkts", "cpktln", LogField::sINT,
&LogAccess::marshal_client_lost_net_pkts, &LogAccess::unmarshal_int_to_str);
// This field is for the number of continuously lost packets during
// transmission from the server to a client on the network layer as
// reported by the client.
//
// For WMT, this is equivalent to c-lost-cont-net
//
ADD_LOG_FIELD("client_lost_continuous_pkts", "cpktlcn", LogField::sINT,
&LogAccess::marshal_client_lost_continuous_pkts, &LogAccess::unmarshal_int_to_str);
// This field is for the number of packets recovered using ECC
// as reported by the client.
//
// For WMT, this is equivalent to c-pkts-recovered-ECC
//
ADD_LOG_FIELD("client_pkts_ecc_recover", "cpktecc", LogField::sINT,
&LogAccess::marshal_client_pkts_ecc_recover, &LogAccess::unmarshal_int_to_str);
// This field is for the number of packets recovered from resent
// requests as reported by the client.
//
// For WMT, this is equivalent to c-pkts-recovered-resent
//
ADD_LOG_FIELD("client_pkts_resent_recover", "crstrc", LogField::sINT,
&LogAccess::marshal_client_pkts_resent_recover, &LogAccess::unmarshal_int_to_str);
// This field is for the number of resend requests sent by the client
// as reported by the client.
//
// For WMT, this is equivalent to c-pkt-resendreqs
//
ADD_LOG_FIELD("client_resend_request", "crstrq", LogField::sINT,
&LogAccess::marshal_client_resend_request, &LogAccess::unmarshal_int_to_str);
// This field is for the number of rebuffers as reported by the
// client.
//
// For WMT, this is equivalent to c-buffercount
//
ADD_LOG_FIELD("client_buffer_count", "cbufc", LogField::sINT,
&LogAccess::marshal_client_buffer_count, &LogAccess::unmarshal_int_to_str);
// This field is the total buffer time of a client in seconds.
//
// For WMT, this is equivalent to c-totalbuffertime
//
ADD_LOG_FIELD("client_buffer_ts", "cbufs", LogField::sINT,
&LogAccess::marshal_client_buffer_ts, &LogAccess::unmarshal_int_to_str);
// This field is the percent quality as reported by the client.
//
// For WMT, this is equivalent to c-quality
//
ADD_LOG_FIELD("client_quality_per", "cqalp", LogField::sINT,
&LogAccess::marshal_client_quality_per, &LogAccess::unmarshal_int_to_str);
#undef ADD_LOG_FIELD
init_status |= FIELDS_INITIALIZED;
}
/*-------------------------------------------------------------------------
Initialization functions
-------------------------------------------------------------------------*/
int
Log::handle_logging_mode_change(const char *name, RecDataT data_type, RecData data, void *cookie)
{
Debug("log2-config", "Enabled status changed");
logging_mode_changed = true;
return 0;
}
void
Log::init(int flags)
{
iObject::Init();
iLogBufferBuffer::Init();
maxInactiveObjects = LOG_OBJECT_ARRAY_DELTA;
numInactiveObjects = 0;
inactive_objects = new LogObject *[maxInactiveObjects];
collation_accept_file_descriptor = NO_FD;
// initialize logging fields
//
init_fields();
// store the configuration flags
//
config_flags = flags;
// create the configuration object
//
config = NEW(new LogConfig);
ink_assert(config != NULL);
// set the logging_mode and initialize
//
if (config_flags & LOGCAT) {
logging_mode = LOG_NOTHING;
} else {
log_rsb = RecAllocateRawStatBlock((int) log_stat_count);
LogConfig::register_configs();
LogConfig::register_stat_callbacks();
config->read_configuration_variables();
collation_port = config->collation_port;
if (config_flags & STANDALONE_COLLATOR) {
logging_mode = LOG_TRANSACTIONS_ONLY;
config->collation_mode = LogConfig::COLLATION_HOST;
} else {
int val = (int) LOG_ConfigReadInteger("proxy.config.log2.logging_enabled");
if (val<LOG_NOTHING || val> FULL_LOGGING) {
logging_mode = FULL_LOGGING;
Warning("proxy.config.log2.logging_enabled has an invalid " "value, setting it to %d", logging_mode);
} else {
logging_mode = (LoggingMode) val;
}
}
config->init();
_init();
// Clear any stat values that need to be reset on startup
//
LOG_CLEAR_DYN_STAT(log2_stat_log_files_open_stat);
LOG_CLEAR_DYN_STAT(log2_stat_log_files_space_used_stat);
/*
The following variables are not cleared at startup, although
we probably should because otherwise their meaning is not very
clear. When did we start counting? Does it make sense to have
these values since the Traffic Server was setup on the
machine?
LOG_CLEAR_DYN_STAT(log2_stat_bytes_written_to_disk_stat);
LOG_CLEAR_DYN_STAT(log2_stat_bytes_sent_to_network_stat);
LOG_CLEAR_DYN_STAT(log2_stat_bytes_received_from_network_stat);
LOG_CLEAR_DYN_STAT(log2_stat_event_log_access_stat);
LOG_CLEAR_DYN_STAT(log2_stat_event_log_access_skip_stat);
LOG_CLEAR_DYN_STAT(log2_stat_event_log_access_fail_stat);
LOG_CLEAR_DYN_STAT(log2_stat_event_log_error_stat);
*/
// if remote management is enabled, do all necessary initialization to
// be able to handle a logging mode change
//
if (!(config_flags & NO_REMOTE_MANAGEMENT)) {
LOG_RegisterConfigUpdateFunc("proxy.config.log2.logging_enabled", &Log::handle_logging_mode_change, NULL);
LOG_RegisterLocalUpdateFunc("proxy.local.log2.collation_mode", &Log::handle_logging_mode_change, NULL);
}
}
}
void
Log::_init()
{
if (!(init_status & FULLY_INITIALIZED)) {
if (!(config_flags & STANDALONE_COLLATOR)) {
// register callbacks
//
if (!(config_flags & NO_REMOTE_MANAGEMENT)) {
LogConfig::register_config_callbacks();
}
LogConfig::register_mgmt_callbacks();
}
// setup global scrap object
//
global_scrap_format = NEW(new LogFormat(TEXT_LOG));
global_scrap_object =
NEW(new LogObject(global_scrap_format,
Log::config->logfile_dir,
"scrapfile.log",
BINARY_LOG, NULL,
Log::config->rolling_enabled,
Log::config->rolling_interval_sec,
Log::config->rolling_offset_hr, Log::config->rolling_size_mb));
// create the flush thread and the collation thread
//
create_threads();
// schedule periodic wakeup
//
//#ifndef INK_SINGLE_THREADED
// eventProcessor.schedule_every (NEW (new PeriodicWakeup()),
// HRTIME_SECOND, ET_CALL);
//#endif // INK_SINGLE_THREADED
init_status |= FULLY_INITIALIZED;
}
Note("logging initialized[%d], logging_mode = %d", init_status, logging_mode);
if (is_debug_tag_set("log2-config")) {
config->display();
}
}
void
Log::create_threads()
{
if (!(init_status & THREADS_CREATED)) {
// start the flush thread
//
// no need for the conditional var since it will be relying on
// on the event system.
ink_mutex_init(&flush_mutex, "Flush thread mutex");
ink_cond_init(&flush_cond);
Continuation *flush_continuation = NEW(new LoggingFlushContinuation);
Event *flush_event = eventProcessor.spawn_thread(flush_continuation);
flush_thread = flush_event->ethread->tid;
#if !defined(IOCORE_LOG_COLLATION)
// start the collation thread if we are not using iocore log collation
//
// for the collation thread, we start one on each machine (done here)
// and then block it on a mutex variable that is only released (from
// LogConfig) on the machine configured to be the collation server.
// When it is no longer needed (say after a reconfiguration), it will
// be blocked again on it's condition variable. This makes it easy to
// start and stop the collation thread, and assumes that there is not
// much overhead associated with keeping an ink_thread blocked on a
// condition variable.
//
ink_mutex_init(&collate_mutex, "Collate thread mutex");
ink_cond_init(&collate_cond);
Continuation *collate_continuation = NEW(new LoggingCollateContinuation);
Event *collate_event = eventProcessor.spawn_thread(collate_continuation);
collate_thread = collate_event->ethread->tid;
#endif
init_status |= THREADS_CREATED;
}
}
/*-------------------------------------------------------------------------
Log::access
Make an entry in the access log for the data supplied by the given
LogAccess object.
-------------------------------------------------------------------------*/
int
Log::access(LogAccess * lad)
{
// See if transaction logging is disabled
//
if (!transaction_logging_enabled()) {
return Log::SKIP;
}
ink_assert(init_status & FULLY_INITIALIZED);
ink_assert(lad != NULL);
int ret;
static long sample = 1;
long this_sample;
// See if we're sampling and it is not time for another sample
//
if (Log::config->sampling_frequency > 1) {
this_sample = sample++;
if (this_sample && this_sample % Log::config->sampling_frequency) {
Debug("log2", "sampling, skipping this entry ...");
ret = Log::SKIP;
goto done;
} else {
Debug("log2", "sampling, LOGGING this entry ...");
sample = 1;
}
}
if (Log::config->log_object_manager.get_num_objects() == 0) {
Debug("log2", "no log objects, skipping this entry ...");
ret = Log::SKIP;
goto done;
}
// initialize this LogAccess object and proccess
//
lad->init();
ret = config->log_object_manager.log(lad);
done:
return ret;
}
/*-------------------------------------------------------------------------
Log::error
Make an entry into the current error log. For convenience, it is given in
both variable argument (format, ...) and stdarg (format, va_list) forms.
Note that Log::error could call Log::va_error after calling va_start
so that va_error handles the statistics update. However, to make
Log::error slightly more efficient this is not the case. The
downside is that one has to be careful to update both functions if
need be.
-------------------------------------------------------------------------*/
int
Log::error(const char *format, ...)
{
int ret_val = Log::SKIP;
if (error_log) {
ink_debug_assert(format != NULL);
va_list ap;
va_start(ap, format);
ret_val = error_log->va_write(format, ap);
va_end(ap);
if (ret_val == Log::LOG_OK) {
ProxyMutex *mutex = this_ethread()->mutex;
LOG_INCREMENT_DYN_STAT(log2_stat_event_log_error_stat);
}
}
return ret_val;
}
int
Log::va_error(char *format, va_list ap)
{
int ret_val = Log::SKIP;
if (error_log) {
ink_debug_assert(format != NULL);
ret_val = error_log->va_write(format, ap);
if (ret_val == Log::LOG_OK) {
ProxyMutex *mutex = this_ethread()->mutex;
LOG_INCREMENT_DYN_STAT(log2_stat_event_log_error_stat);
}
}
return ret_val;
}
/*-------------------------------------------------------------------------
Log::flush_thread_main
This function defines the functionality of the logging flush thread,
whose purpose is to consume LogBuffer objects from the
global_buffer_full_list, process them, and destroy them.
-------------------------------------------------------------------------*/
void *
Log::flush_thread_main(void *args)
{
time_t now, last_time = 0;
size_t total_bytes, bytes_to_disk, bytes_to_net, bytes_to_pipe;
Debug("log2-flush", "Log flush thread is alive ...");
while (true) {
ink_timestruc timeout_time;
bytes_to_disk = (bytes_to_net = (bytes_to_pipe = 0));
total_bytes = config->log_object_manager.flush_buffers(&bytes_to_disk, &bytes_to_net, &bytes_to_pipe);
if (error_log)
total_bytes += error_log->flush_buffers(&bytes_to_disk, &bytes_to_net, &bytes_to_pipe);
config->increment_space_used(bytes_to_disk);
// Update statistics
//
LOG_SUM_GLOBAL_DYN_STAT(log2_stat_bytes_written_to_disk_stat, bytes_to_disk);
LOG_SUM_GLOBAL_DYN_STAT(log2_stat_bytes_sent_to_network_stat, bytes_to_net);
Debug("log2-flush", "%d bytes flushed this round [ %d to disk, %d to net, %d to pipe]",
total_bytes, bytes_to_disk, bytes_to_net, bytes_to_pipe);
// Time to work on periodic events??
//
now = time(NULL);
if (now > last_time) {
Debug("log2-flush", "periodic tasks for %ld", now);
periodic_tasks(now);
last_time = (now = time(NULL));
}
// wait for more work; a spurious wake-up is ok since we'll just
// check the queue and find there is nothing to do, then wait
// again.
//
//ink_cond_wait (&flush_cond, &flush_mutex);
// vl: we should use ink_cond_timedwait in order to be sure that this thread is alive at least once per second
// to execute periodic_tasks()
memset(&timeout_time, 0, sizeof(timeout_time));
ink_mutex_acquire(&flush_mutex);
while (flush_counter < FLUSH_THREAD_MIN_FLUSH_COUNTER && now <= last_time) {
timeout_time.tv_sec = (now = time(NULL)) + FLUSH_THREAD_SLEEP_TIMEOUT;
if (ink_cond_timedwait(&flush_cond, &flush_mutex, &timeout_time) == ETIMEDOUT)
break;
}
flush_counter = 0;
ink_mutex_release(&flush_mutex);
}
/* NOTREACHED */
return args;
}
/*-------------------------------------------------------------------------
Log::collate_thread_main
This function defines the functionality of the log collation thread,
whose purpose is to collate log buffers from other nodes.
-------------------------------------------------------------------------*/
void *
Log::collate_thread_main(void *args)
{
NOWARN_UNUSED(args);
LogSock *sock;
LogBufferHeader *header;
LogFormat *format;
LogObject *obj;
int bytes_read;
int sock_id;
int new_client;
Debug("log2-thread", "Log collation thread is alive ...");
while (true) {
ink_assert(Log::config != NULL);
// wait on the collation condition variable until we're sure that
// we're a collation host. The while loop guards against spurious
// wake-ups.
//
while (!Log::config->am_collation_host()) {
ink_cond_wait(&collate_cond, &collate_mutex);
}
// Ok, at this point we know we're a log collation host, so get to
// work. We still need to keep checking whether we're a collation
// host to account for a reconfiguration.
//
Debug("log2-sock", "collation thread starting, creating LogSock");
sock = NEW(new LogSock(LogSock::LS_CONST_CLUSTER_MAX_MACHINES));
ink_assert(sock != NULL);
if (sock->listen(Log::config->collation_port) != 0) {
LogUtils::manager_alarm(LogUtils::LOG_ALARM_ERROR,
"Collation server error; could not listen on port %d", Log::config->collation_port);
Warning("Collation server error; could not listen on port %d", Log::config->collation_port);
delete sock;
//
// go to sleep ...
//
ink_cond_wait(&collate_cond, &collate_mutex);
continue;
}
while (true) {
if (!Log::config->am_collation_host()) {
break;
}
if (sock->pending_connect(0)) {
Debug("log2-sock", "pending connection ...");
if ((new_client = sock->accept()) < 0) {
Debug("log2-sock", "error accepting new collation client");
} else {
Debug("log2-sock", "connection %d accepted", new_client);
if (!sock->authorized_client(new_client, Log::config->collation_secret)) {
Warning("Unauthorized client connecting to " "log collation port; connection refused.");
sock->close(new_client);
}
}
}
sock->check_connections();
if (!sock->pending_message_any(&sock_id, 0)) {
continue;
}
Debug("log2-sock", "pending message ...");
header = (LogBufferHeader *) sock->read_alloc(sock_id, &bytes_read);
if (!header) {
Debug("log2-sock", "Error reading LogBuffer from collation client");
continue;
}
unsigned version = ntohl(header->version);
if (version != LOG_SEGMENT_VERSION) {
Note("Invalid LogBuffer received; invalid version - "
"buffer = %u, current = %u", version, LOG_SEGMENT_VERSION);
delete[]header;
continue;
}
Debug("log2-sock", "message accepted, size = %d", bytes_read);
LOG_SUM_GLOBAL_DYN_STAT(log2_stat_bytes_received_from_network_stat, bytes_read);
obj = match_logobject(header);
if (!obj) {
Note("LogObject not found with fieldlist id; " "writing LogBuffer to scrap file");
obj = global_scrap_object;
}
format = obj->m_format;
Debug("log2-sock", "Using format '%s'", format->name());
delete[]header;
// vl: absolutely useless code because 'global_buffer_full_list' is not used anywhere
// buffer = NEW (new LogBuffer (obj, header));
// buffer->convert_to_host_order();
// Log::global_buffer_full_list.add (buffer);
// ink_mutex_acquire (&flush_mutex);
// ink_cond_signal (&Log::flush_cond);
// ink_mutex_release (&flush_mutex);
}
Debug("log2", "no longer collation host, deleting LogSock");
delete sock;
}
/* NOTREACHED */
return NULL;
}
/*-------------------------------------------------------------------------
Log::match_logobject
This routine matches the given buffer with the local list of LogObjects.
If a match cannot be found, then we'll try to construct a local LogObject
using the information provided in the header. If all else fails, we
return NULL.
-------------------------------------------------------------------------*/
LogObject *
Log::match_logobject(LogBufferHeader * header)
{
if (!header)
return NULL;
LogObject *obj;
obj = Log::config->log_object_manager.get_object_with_signature(header->log_object_signature);
if (!obj) {
// object does not exist yet, create it
//
LogFormat *fmt = NEW(new LogFormat("__collation_format__",
header->fmt_fieldlist(),
header->fmt_printf()));
if (fmt->valid()) {
LogFileFormat file_format =
header->log_object_flags & LogObject::BINARY ? BINARY_LOG :
(header->log_object_flags & LogObject::WRITES_TO_PIPE ? ASCII_PIPE : ASCII_LOG);
obj = NEW(new LogObject(fmt, Log::config->logfile_dir,
header->log_filename(), file_format, NULL,
Log::config->rolling_enabled,
Log::config->rolling_interval_sec,
Log::config->rolling_offset_hr, Log::config->rolling_size_mb));
obj->set_remote_flag();
if (Log::config->log_object_manager.manage_object(obj)) {
// object manager can't solve filename conflicts
// delete the object and return NULL
//
delete obj;
obj = NULL;
}
}
}
return obj;
}