blob: 512bbe87cc5055a674e06f399296997603cf2a2c [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.
*/
/***************************************************************************
LogField.cc
This file implements the LogField object, which is the central
representation of a logging field.
***************************************************************************/
#include "libts.h"
#include "Error.h"
#include "Resource.h"
#include "LogUtils.h"
#include "LogField.h"
#include "LogBuffer.h"
#include "LogAccess.h"
#include "Log.h"
const char *container_names[] = {
"not-a-container",
"cqh",
"psh",
"pqh",
"ssh",
"ecqh",
"epsh",
"epqh",
"essh",
"icfg",
"scfg",
"record",
""
};
const char *aggregate_names[] = {
"not-an-agg-op",
"COUNT",
"SUM",
"AVG",
"FIRST",
"LAST",
""
};
/*-------------------------------------------------------------------------
LogField::LogField
-------------------------------------------------------------------------*/
// Generic field ctor
LogField::LogField(const char *name, const char *symbol, Type type, MarshalFunc marshal, UnmarshalFunc unmarshal)
:
m_name(xstrdup(name)), m_symbol(xstrdup(symbol)), m_type(type), m_container(NO_CONTAINER), m_marshal_func(marshal),
m_unmarshal_func(unmarshal), m_unmarshal_func_map(NULL), m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0),
m_time_field(false), m_alias_map(0)
{
ink_assert(m_name != NULL);
ink_assert(m_symbol != NULL);
ink_assert(m_type >= 0 && m_type < N_TYPES);
ink_assert(m_marshal_func != (MarshalFunc) NULL);
m_time_field = (strcmp(m_symbol, "cqts") == 0
|| strcmp(m_symbol, "cqth") == 0
|| strcmp(m_symbol, "cqtq") == 0
|| strcmp(m_symbol, "cqtn") == 0 || strcmp(m_symbol, "cqtd") == 0 || strcmp(m_symbol, "cqtt") == 0);
}
LogField::LogField(const char *name, const char *symbol, Type type,
MarshalFunc marshal, UnmarshalFuncWithMap unmarshal, Ptr<LogFieldAliasMap> map)
:
m_name(xstrdup(name)), m_symbol(xstrdup(symbol)), m_type(type), m_container(NO_CONTAINER), m_marshal_func(marshal),
m_unmarshal_func(NULL), m_unmarshal_func_map(unmarshal), m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0),
m_time_field(false), m_alias_map(map)
{
ink_assert(m_name != NULL);
ink_assert(m_symbol != NULL);
ink_assert(m_type >= 0 && m_type < N_TYPES);
ink_assert(m_marshal_func != (MarshalFunc) NULL);
ink_assert(m_alias_map != NULL);
m_time_field = (strcmp(m_symbol, "cqts") == 0
|| strcmp(m_symbol, "cqth") == 0
|| strcmp(m_symbol, "cqtq") == 0
|| strcmp(m_symbol, "cqtn") == 0 || strcmp(m_symbol, "cqtd") == 0 || strcmp(m_symbol, "cqtt") == 0);
}
// Container field ctor
LogField::LogField(const char *field, Container container)
:
m_name(xstrdup(field))
,
m_symbol(xstrdup(container_names[container]))
,
m_type(LogField::STRING)
,
m_container(container)
,
m_marshal_func(NULL)
,
m_unmarshal_func(NULL)
,
m_unmarshal_func_map(NULL)
,
m_agg_op(NO_AGGREGATE)
,
m_agg_cnt(0)
,
m_agg_val(0)
,
m_time_field(false)
,
m_alias_map(0)
{
ink_assert(m_name != NULL);
ink_assert(m_symbol != NULL);
ink_assert(m_type >= 0 && m_type < N_TYPES);
m_time_field = (strcmp(m_symbol, "cqts") == 0
|| strcmp(m_symbol, "cqth") == 0
|| strcmp(m_symbol, "cqtq") == 0
|| strcmp(m_symbol, "cqtn") == 0 || strcmp(m_symbol, "cqtd") == 0 || strcmp(m_symbol, "cqtt") == 0);
switch (m_container) {
case CQH:
case PSH:
case PQH:
case SSH:
case ECQH:
case EPSH:
case EPQH:
case ESSH:
case SCFG:
m_unmarshal_func = &(LogAccess::unmarshal_str);
break;
case ICFG:
m_unmarshal_func = &(LogAccess::unmarshal_int_to_str);
break;
case RECORD:
m_unmarshal_func = &(LogAccess::unmarshal_record);
break;
default:
Note("Invalid container type in LogField ctor: %d", container);
}
}
// Copy ctor
LogField::LogField(const LogField & rhs)
:
m_name(xstrdup(rhs.m_name))
,
m_symbol(xstrdup(rhs.m_symbol))
,
m_type(rhs.m_type)
,
m_container(rhs.m_container)
,
m_marshal_func(rhs.m_marshal_func)
,
m_unmarshal_func(rhs.m_unmarshal_func)
,
m_unmarshal_func_map(rhs.m_unmarshal_func_map)
,
m_agg_op(rhs.m_agg_op)
,
m_agg_cnt(0)
,
m_agg_val(0)
,
m_time_field(rhs.m_time_field)
,
m_alias_map(rhs.m_alias_map)
{
ink_assert(m_name != NULL);
ink_assert(m_symbol != NULL);
ink_assert(m_type >= 0 && m_type < N_TYPES);
}
/*-------------------------------------------------------------------------
LogField::~LogField
-------------------------------------------------------------------------*/
LogField::~LogField()
{
xfree(m_name);
xfree(m_symbol);
}
/*-------------------------------------------------------------------------
LogField::marshal_len
This routine will find the marshalling length (in bytes) for this field,
given a LogAccess object. It does this by using the property of the
marshalling routines that if the marshal buffer is NULL, only the size
requirement is returned.
-------------------------------------------------------------------------*/
unsigned
LogField::marshal_len(LogAccess * lad)
{
if (m_container == NO_CONTAINER) {
return (lad->*m_marshal_func) (NULL);
}
switch (m_container) {
case CQH:
case PSH:
case PQH:
case SSH:
return lad->marshal_http_header_field(m_container, m_name, NULL);
case ECQH:
case EPSH:
case EPQH:
case ESSH:
return lad->marshal_http_header_field_escapify(m_container, m_name, NULL);
case ICFG:
return lad->marshal_config_int_var(m_name, NULL);
case SCFG:
return lad->marshal_config_str_var(m_name, NULL);
case RECORD:
return lad->marshal_record(m_name, NULL);
default:
return 0;
}
}
/*-------------------------------------------------------------------------
LogField::marshal
This routine will marshsal the given field into the buffer provided.
-------------------------------------------------------------------------*/
unsigned
LogField::marshal(LogAccess * lad, char *buf)
{
if (m_container == NO_CONTAINER) {
return (lad->*m_marshal_func) (buf);
}
switch (m_container) {
case CQH:
case PSH:
case PQH:
case SSH:
return lad->marshal_http_header_field(m_container, m_name, buf);
case ECQH:
case EPSH:
case EPQH:
case ESSH:
return lad->marshal_http_header_field_escapify(m_container, m_name, buf);
case ICFG:
return lad->marshal_config_int_var(m_name, buf);
case SCFG:
return lad->marshal_config_str_var(m_name, buf);
case RECORD:
return lad->marshal_record(m_name, buf);
default:
return 0;
}
}
/*-------------------------------------------------------------------------
LogField::marshal_agg
-------------------------------------------------------------------------*/
unsigned
LogField::marshal_agg(char *buf)
{
ink_assert(buf != NULL);
int64_t avg = 0;
switch (m_agg_op) {
case eCOUNT:
LogAccess::marshal_int(buf, m_agg_cnt);
break;
case eSUM:
case eFIRST:
case eLAST:
LogAccess::marshal_int(buf, m_agg_val);
break;
case eAVG:
if (m_agg_cnt) {
avg = m_agg_val / m_agg_cnt;
}
LogAccess::marshal_int(buf, avg);
break;
default:
Note("Cannot marshal aggregate field %s; " "invalid aggregate operator: %d", m_symbol, m_agg_op);
return 0;
}
m_agg_val = 0;
m_agg_cnt = 0;
return INK_MIN_ALIGN;
}
/*-------------------------------------------------------------------------
LogField::unmarshal
This routine will invoke the proper unmarshalling routine to return a
string that represents the ASCII value of the field.
-------------------------------------------------------------------------*/
unsigned
LogField::unmarshal(char **buf, char *dest, int len)
{
if (m_alias_map == NULL) {
return (*m_unmarshal_func) (buf, dest, len);
} else {
return (*m_unmarshal_func_map) (buf, dest, len, m_alias_map);
}
}
/*-------------------------------------------------------------------------
LogField::display
-------------------------------------------------------------------------*/
void
LogField::display(FILE * fd)
{
static const char *names[LogField::N_TYPES] = {
"sINT",
"dINT",
"STR"
};
fprintf(fd, " %30s %10s %5s\n", m_name, m_symbol, names[m_type]);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
void
LogField::set_aggregate_op(LogField::Aggregate agg_op)
{
if (agg_op > 0 && agg_op < LogField::N_AGGREGATES) {
m_agg_op = agg_op;
} else {
Note("Invalid aggregate operator identifier: %d", agg_op);
m_agg_op = NO_AGGREGATE;
}
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
void
LogField::update_aggregate(int64_t val)
{
switch (m_agg_op) {
case eCOUNT:
case eSUM:
case eAVG:
m_agg_val += val;
m_agg_cnt++;
break;
case eFIRST:
if (m_agg_cnt == 0) {
m_agg_val = val;
m_agg_cnt++;
}
break;
case eLAST:
m_agg_val = val;
m_agg_cnt++;
break;
default:
Note("Cannot update aggregate field; invalid operator %d", m_agg_op);
return;
}
Debug("log-agg", "Aggregate field %s updated with val %d, "
"new val = %d, cnt = %d", m_symbol, val, m_agg_val, m_agg_cnt);
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
LogField::Container LogField::valid_container_name(char *name)
{
for (int i = 1; i < LogField::N_CONTAINERS; i++) {
if (strcmp(name, container_names[i]) == 0) {
return (LogField::Container) i;
}
}
return LogField::NO_CONTAINER;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
LogField::Aggregate LogField::valid_aggregate_name(char *name)
{
for (int i = 1; i < LogField::N_AGGREGATES; i++) {
if (strcmp(name, aggregate_names[i]) == 0) {
return (LogField::Aggregate) i;
}
}
return LogField::NO_AGGREGATE;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
bool LogField::fieldlist_contains_aggregates(char *fieldlist)
{
bool
contains_aggregates = false;
for (int i = 1; i < LogField::N_AGGREGATES; i++) {
if (strstr(fieldlist, aggregate_names[i]) != NULL) {
contains_aggregates = true;
}
}
return contains_aggregates;
}
/*-------------------------------------------------------------------------
LogFieldList
It is ASSUMED that each element on this list has been allocated from the
heap with "new" and that each element is on at most ONE list. To enforce
this, items are copied by default, using the copy ctor.
-------------------------------------------------------------------------*/
LogFieldList::LogFieldList()
:m_marshal_len(0)
{
}
LogFieldList::~LogFieldList()
{
clear();
}
void
LogFieldList::clear()
{
LogField *f;
while ((f = m_field_list.dequeue())) {
delete f; // safe given the semantics stated above
}
m_marshal_len = 0;
}
void
LogFieldList::add(LogField * field, bool copy)
{
ink_assert(field != NULL);
if (copy) {
m_field_list.enqueue(NEW(new LogField(*field)));
} else {
m_field_list.enqueue(field);
}
if (field->type() == LogField::sINT) {
m_marshal_len += INK_MIN_ALIGN;
}
}
LogField *
LogFieldList::find_by_name(const char *name) const
{
for (LogField * f = first(); f; f = next(f)) {
if (!strcmp(f->name(), name)) {
return f;
}
}
return NULL;
}
LogField *
LogFieldList::find_by_symbol(const char *symbol) const
{
LogField *field = 0;
if (Log::field_symbol_hash) {
if (ink_hash_table_lookup(Log::field_symbol_hash, (char *) symbol, (InkHashTableValue *) & field) && field) {
Debug("log-field-hash", "Field %s found", field->symbol());
return field;
}
}
// trusty old method
for (field = first(); field; field = next(field)) {
if (!strcmp(field->symbol(), symbol)) {
return field;
}
}
return NULL;
}
unsigned
LogFieldList::marshal_len(LogAccess * lad)
{
int bytes = 0;
for (LogField * f = first(); f; f = next(f)) {
if (f->type() != LogField::sINT) {
bytes += f->marshal_len(lad);
}
}
return m_marshal_len + bytes;
}
unsigned
LogFieldList::marshal(LogAccess * lad, char *buf)
{
char *ptr;
int bytes = 0;
for (LogField * f = first(); f; f = next(f)) {
ptr = &buf[bytes];
bytes += f->marshal(lad, ptr);
ink_debug_assert(bytes % INK_MIN_ALIGN == 0);
}
return bytes;
}
unsigned
LogFieldList::marshal_agg(char *buf)
{
char *ptr;
int bytes = 0;
for (LogField * f = first(); f; f = next(f)) {
ptr = &buf[bytes];
bytes += f->marshal_agg(ptr);
}
return bytes;
}
unsigned
LogFieldList::count()
{
unsigned cnt = 0;
for (LogField * f = first(); f; f = next(f)) {
cnt++;
}
return cnt;
}
void
LogFieldList::display(FILE * fd)
{
for (LogField * f = first(); f; f = next(f)) {
f->display(fd);
}
}