• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

LogField.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 /***************************************************************************
00025  LogField.cc
00026 
00027  This file implements the LogField object, which is the central
00028  representation of a logging field.
00029  ***************************************************************************/
00030 #include "libts.h"
00031 
00032 #include "Error.h"
00033 #include "LogUtils.h"
00034 #include "LogField.h"
00035 #include "LogBuffer.h"
00036 #include "LogAccess.h"
00037 #include "Log.h"
00038 
00039 const char *container_names[] = {
00040   "not-a-container",
00041   "cqh",
00042   "psh",
00043   "pqh",
00044   "ssh",
00045   "cssh",
00046   "ecqh",
00047   "epsh",
00048   "epqh",
00049   "essh",
00050   "ecssh",
00051   "icfg",
00052   "scfg",
00053   "record",
00054   ""
00055 };
00056 
00057 const char *aggregate_names[] = {
00058   "not-an-agg-op",
00059   "COUNT",
00060   "SUM",
00061   "AVG",
00062   "FIRST",
00063   "LAST",
00064   ""
00065 };
00066 
00067 LogSlice::LogSlice(char *str)
00068 {
00069   char *a, *b, *c;
00070 
00071   m_enable = false;
00072   m_start = 0;
00073   m_end = INT_MAX;
00074 
00075   if ((a = strchr(str, '[')) == NULL)
00076     return;
00077 
00078   *a++ = '\0';
00079   if ((b = strchr(a, ':')) == NULL)
00080     return;
00081 
00082   *b++ = '\0';
00083   if ((c = strchr(b, ']')) == NULL)
00084     return;
00085 
00086   m_enable = true;
00087 
00088   // eat space
00089   while (a != b && *a == ' ') a++;
00090 
00091   if (a != b)
00092     m_start = atoi(a);
00093 
00094   // eat space
00095   while (b != c && *b == ' ') b++;
00096 
00097   if (b != c)
00098     m_end = atoi(b);
00099 }
00100 
00101 int
00102 LogSlice::toStrOffset(int strlen, int *offset)
00103 {
00104   int i, j, len;
00105 
00106   // letf index
00107   if (m_start >= 0)
00108     i = m_start;
00109   else
00110     i = m_start + strlen;
00111 
00112   if (i >= strlen)
00113     return 0;
00114 
00115   if (i < 0)
00116     i = 0;
00117 
00118   // right index
00119   if (m_end >= 0)
00120     j = m_end;
00121   else
00122     j = m_end + strlen;
00123 
00124   if (j <= 0)
00125     return 0;
00126 
00127   if (j > strlen)
00128     j = strlen;
00129 
00130   // available length
00131   len = j - i;
00132 
00133   if (len > 0)
00134     *offset = i;
00135 
00136   return len;
00137 }
00138 
00139 /*-------------------------------------------------------------------------
00140   LogField::LogField
00141   -------------------------------------------------------------------------*/
00142 
00143 // Generic field ctor
00144 LogField::LogField(const char *name, const char *symbol, Type type, MarshalFunc marshal, UnmarshalFunc unmarshal, SetFunc _setfunc)
00145   : m_name(ats_strdup(name)), m_symbol(ats_strdup(symbol)), m_type(type), m_container(NO_CONTAINER), m_marshal_func(marshal),
00146     m_unmarshal_func(unmarshal), m_unmarshal_func_map(NULL), m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0),
00147     m_time_field(false), m_alias_map(0), m_set_func(_setfunc)
00148 {
00149   ink_assert(m_name != NULL);
00150   ink_assert(m_symbol != NULL);
00151   ink_assert(m_type >= 0 && m_type < N_TYPES);
00152   ink_assert(m_marshal_func != (MarshalFunc) NULL);
00153 
00154   m_time_field = (strcmp(m_symbol, "cqts") == 0
00155                   || strcmp(m_symbol, "cqth") == 0
00156                   || strcmp(m_symbol, "cqtq") == 0
00157                   || strcmp(m_symbol, "cqtn") == 0 || strcmp(m_symbol, "cqtd") == 0 || strcmp(m_symbol, "cqtt") == 0);
00158 }
00159 
00160 LogField::LogField(const char *name, const char *symbol, Type type,
00161                    MarshalFunc marshal, UnmarshalFuncWithMap unmarshal, Ptr<LogFieldAliasMap> map, SetFunc _setfunc)
00162   : m_name(ats_strdup(name)), m_symbol(ats_strdup(symbol)), m_type(type), m_container(NO_CONTAINER), m_marshal_func(marshal),
00163     m_unmarshal_func(NULL), m_unmarshal_func_map(unmarshal), m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0),
00164     m_time_field(false), m_alias_map(map), m_set_func(_setfunc)
00165 {
00166   ink_assert(m_name != NULL);
00167   ink_assert(m_symbol != NULL);
00168   ink_assert(m_type >= 0 && m_type < N_TYPES);
00169   ink_assert(m_marshal_func != (MarshalFunc) NULL);
00170   ink_assert(m_alias_map != NULL);
00171 
00172   m_time_field = (strcmp(m_symbol, "cqts") == 0
00173                   || strcmp(m_symbol, "cqth") == 0
00174                   || strcmp(m_symbol, "cqtq") == 0
00175                   || strcmp(m_symbol, "cqtn") == 0 || strcmp(m_symbol, "cqtd") == 0 || strcmp(m_symbol, "cqtt") == 0);
00176 }
00177 
00178 // Container field ctor
00179 LogField::LogField(const char *field, Container container, SetFunc _setfunc)
00180   : m_name(ats_strdup(field)), m_symbol(ats_strdup(container_names[container])), m_type(LogField::STRING),
00181     m_container(container), m_marshal_func(NULL), m_unmarshal_func(NULL), m_unmarshal_func_map(NULL),
00182     m_agg_op(NO_AGGREGATE), m_agg_cnt(0), m_agg_val(0), m_time_field(false), m_alias_map(0), m_set_func(_setfunc)
00183 {
00184   ink_assert(m_name != NULL);
00185   ink_assert(m_symbol != NULL);
00186   ink_assert(m_type >= 0 && m_type < N_TYPES);
00187 
00188   m_time_field = (strcmp(m_symbol, "cqts") == 0
00189                   || strcmp(m_symbol, "cqth") == 0
00190                   || strcmp(m_symbol, "cqtq") == 0
00191                   || strcmp(m_symbol, "cqtn") == 0 || strcmp(m_symbol, "cqtd") == 0 || strcmp(m_symbol, "cqtt") == 0);
00192 
00193   switch (m_container) {
00194   case CQH:
00195   case PSH:
00196   case PQH:
00197   case SSH:
00198   case CSSH:
00199   case ECQH:
00200   case EPSH:
00201   case EPQH:
00202   case ESSH:
00203   case ECSSH:
00204   case SCFG:
00205     m_unmarshal_func = (UnmarshalFunc)&(LogAccess::unmarshal_str);
00206     break;
00207 
00208   case ICFG:
00209     m_unmarshal_func = &(LogAccess::unmarshal_int_to_str);
00210     break;
00211 
00212   case RECORD:
00213     m_unmarshal_func = &(LogAccess::unmarshal_record);
00214     break;
00215 
00216   default:
00217     Note("Invalid container type in LogField ctor: %d", container);
00218   }
00219 }
00220 
00221 // Copy ctor
00222 LogField::LogField(const LogField &rhs)
00223   : m_name(ats_strdup(rhs.m_name)), m_symbol(ats_strdup(rhs.m_symbol)), m_type(rhs.m_type), m_container(rhs.m_container),
00224     m_marshal_func(rhs.m_marshal_func), m_unmarshal_func(rhs.m_unmarshal_func), m_unmarshal_func_map(rhs.m_unmarshal_func_map),
00225     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), m_set_func(rhs.m_set_func)
00226 {
00227   ink_assert(m_name != NULL);
00228   ink_assert(m_symbol != NULL);
00229   ink_assert(m_type >= 0 && m_type < N_TYPES);
00230 }
00231 
00232 /*-------------------------------------------------------------------------
00233   LogField::~LogField
00234   -------------------------------------------------------------------------*/
00235 LogField::~LogField()
00236 {
00237   ats_free(m_name);
00238   ats_free(m_symbol);
00239 }
00240 
00241 /*-------------------------------------------------------------------------
00242   LogField::marshal_len
00243 
00244   This routine will find the marshalling length (in bytes) for this field,
00245   given a LogAccess object.  It does this by using the property of the
00246   marshalling routines that if the marshal buffer is NULL, only the size
00247   requirement is returned.
00248   -------------------------------------------------------------------------*/
00249 unsigned
00250 LogField::marshal_len(LogAccess *lad)
00251 {
00252   if (m_container == NO_CONTAINER)
00253     return (lad->*m_marshal_func) (NULL);
00254 
00255   switch (m_container) {
00256   case CQH:
00257   case PSH:
00258   case PQH:
00259   case SSH:
00260   case CSSH:
00261     return lad->marshal_http_header_field(m_container, m_name, NULL);
00262 
00263   case ECQH:
00264   case EPSH:
00265   case EPQH:
00266   case ESSH:
00267   case ECSSH:
00268     return lad->marshal_http_header_field_escapify(m_container, m_name, NULL);
00269 
00270   case ICFG:
00271     return lad->marshal_config_int_var(m_name, NULL);
00272 
00273   case SCFG:
00274     return lad->marshal_config_str_var(m_name, NULL);
00275 
00276   case RECORD:
00277     return lad->marshal_record(m_name, NULL);
00278 
00279   default:
00280     return 0;
00281   }
00282 }
00283 
00284 void
00285 LogField::updateField(LogAccess *lad, char *buf, int len)
00286 {
00287   if (m_container == NO_CONTAINER) {
00288     return (lad->*m_set_func) (buf, len);
00289   }
00290   // else...// future enhancement
00291 }
00292 
00293 /*-------------------------------------------------------------------------
00294   LogField::marshal
00295 
00296   This routine will marshsal the given field into the buffer provided.
00297   -------------------------------------------------------------------------*/
00298 unsigned
00299 LogField::marshal(LogAccess *lad, char *buf)
00300 {
00301   if (m_container == NO_CONTAINER) {
00302     return (lad->*m_marshal_func) (buf);
00303   }
00304 
00305   switch (m_container) {
00306   case CQH:
00307   case PSH:
00308   case PQH:
00309   case SSH:
00310   case CSSH:
00311     return lad->marshal_http_header_field(m_container, m_name, buf);
00312 
00313   case ECQH:
00314   case EPSH:
00315   case EPQH:
00316   case ESSH:
00317   case ECSSH:
00318     return lad->marshal_http_header_field_escapify(m_container, m_name, buf);
00319 
00320   case ICFG:
00321     return lad->marshal_config_int_var(m_name, buf);
00322 
00323   case SCFG:
00324     return lad->marshal_config_str_var(m_name, buf);
00325 
00326   case RECORD:
00327     return lad->marshal_record(m_name, buf);
00328 
00329   default:
00330     return 0;
00331   }
00332 }
00333 
00334 /*-------------------------------------------------------------------------
00335   LogField::marshal_agg
00336   -------------------------------------------------------------------------*/
00337 unsigned
00338 LogField::marshal_agg(char *buf)
00339 {
00340   ink_assert(buf != NULL);
00341   int64_t avg = 0;
00342 
00343   switch (m_agg_op) {
00344 
00345   case eCOUNT:
00346     LogAccess::marshal_int(buf, m_agg_cnt);
00347     break;
00348 
00349   case eSUM:
00350   case eFIRST:
00351   case eLAST:
00352     LogAccess::marshal_int(buf, m_agg_val);
00353     break;
00354 
00355   case eAVG:
00356     if (m_agg_cnt) {
00357       avg = m_agg_val / m_agg_cnt;
00358     }
00359     LogAccess::marshal_int(buf, avg);
00360     break;
00361 
00362   default:
00363     Note("Cannot marshal aggregate field %s; " "invalid aggregate operator: %d", m_symbol, m_agg_op);
00364     return 0;
00365   }
00366 
00367   m_agg_val = 0;
00368   m_agg_cnt = 0;
00369 
00370   return INK_MIN_ALIGN;
00371 }
00372 
00373 /*-------------------------------------------------------------------------
00374   LogField::unmarshal
00375 
00376   This routine will invoke the proper unmarshalling routine to return a
00377   string that represents the ASCII value of the field.
00378   -------------------------------------------------------------------------*/
00379 unsigned
00380 LogField::unmarshal(char **buf, char *dest, int len)
00381 {
00382   if (m_alias_map == NULL) {
00383     if (m_unmarshal_func == (UnmarshalFunc)LogAccess::unmarshal_str
00384         || m_unmarshal_func == (UnmarshalFunc)LogAccess::unmarshal_http_text) {
00385       UnmarshalFuncWithSlice func = (UnmarshalFuncWithSlice)m_unmarshal_func;
00386       return (*func) (buf, dest, len, &m_slice);
00387     }
00388     return (*m_unmarshal_func) (buf, dest, len);
00389   } else {
00390     return (*m_unmarshal_func_map) (buf, dest, len, m_alias_map);
00391   }
00392 }
00393 
00394 /*-------------------------------------------------------------------------
00395   LogField::display
00396   -------------------------------------------------------------------------*/
00397 void
00398 LogField::display(FILE *fd)
00399 {
00400   static const char *names[LogField::N_TYPES] = {
00401     "sINT",
00402     "dINT",
00403     "STR",
00404     "IP"
00405   };
00406 
00407   fprintf(fd, "    %30s %10s %5s\n", m_name, m_symbol, names[m_type]);
00408 }
00409 
00410 /*-------------------------------------------------------------------------
00411   LogField::operator==
00412 
00413   This operator does only care of the name and m_symbol, may need
00414   do check on others layter.
00415   -------------------------------------------------------------------------*/
00416 bool
00417 LogField::operator==(LogField & rhs) {
00418   if (strcmp(name(), rhs.name()) || strcmp(symbol(), rhs.symbol())) {
00419     return false;
00420   } else {
00421     return true;
00422   }
00423 }
00424 
00425 /*-------------------------------------------------------------------------
00426   -------------------------------------------------------------------------*/
00427 void
00428 LogField::set_aggregate_op(LogField::Aggregate agg_op)
00429 {
00430   if (agg_op > 0 && agg_op < LogField::N_AGGREGATES) {
00431     m_agg_op = agg_op;
00432   } else {
00433     Note("Invalid aggregate operator identifier: %d", agg_op);
00434     m_agg_op = NO_AGGREGATE;
00435   }
00436 }
00437 
00438 
00439 void
00440 LogField::update_aggregate(int64_t val)
00441 {
00442   switch (m_agg_op) {
00443 
00444   case eCOUNT:
00445   case eSUM:
00446   case eAVG:
00447     m_agg_val += val;
00448     m_agg_cnt++;
00449     break;
00450 
00451   case eFIRST:
00452     if (m_agg_cnt == 0) {
00453       m_agg_val = val;
00454       m_agg_cnt++;
00455     }
00456     break;
00457 
00458   case eLAST:
00459     m_agg_val = val;
00460     m_agg_cnt++;
00461     break;
00462 
00463   default:
00464     Note("Cannot update aggregate field; invalid operator %d", m_agg_op);
00465     return;
00466   }
00467 
00468   Debug("log-agg", "Aggregate field %s updated with val %" PRId64", "
00469         "new val = %" PRId64", cnt = %" PRId64"", m_symbol, val, m_agg_val, m_agg_cnt);
00470 }
00471 
00472 
00473 LogField::Container LogField::valid_container_name(char *name)
00474 {
00475   for (int i = 1; i < LogField::N_CONTAINERS; i++) {
00476     if (strcmp(name, container_names[i]) == 0) {
00477       return (LogField::Container) i;
00478     }
00479   }
00480   return LogField::NO_CONTAINER;
00481 }
00482 
00483 
00484 LogField::Aggregate LogField::valid_aggregate_name(char *name)
00485 {
00486   for (int i = 1; i < LogField::N_AGGREGATES; i++) {
00487     if (strcmp(name, aggregate_names[i]) == 0) {
00488       return (LogField::Aggregate) i;
00489     }
00490   }
00491   return LogField::NO_AGGREGATE;
00492 }
00493 
00494 
00495 bool LogField::fieldlist_contains_aggregates(char *fieldlist)
00496 {
00497   bool
00498     contains_aggregates = false;
00499   for (int i = 1; i < LogField::N_AGGREGATES; i++) {
00500     if (strstr(fieldlist, aggregate_names[i]) != NULL) {
00501       contains_aggregates = true;
00502     }
00503   }
00504   return contains_aggregates;
00505 }
00506 
00507 
00508 /*-------------------------------------------------------------------------
00509   LogFieldList
00510 
00511   It is ASSUMED that each element on this list has been allocated from the
00512   heap with "new" and that each element is on at most ONE list.  To enforce
00513   this, items are copied by default, using the copy ctor.
00514   -------------------------------------------------------------------------*/
00515 LogFieldList::LogFieldList()
00516   : m_marshal_len(0)
00517 { }
00518 
00519 LogFieldList::~LogFieldList()
00520 {
00521   clear();
00522 }
00523 
00524 void
00525 LogFieldList::clear()
00526 {
00527   LogField *f;
00528   while ((f = m_field_list.dequeue())) {
00529     delete f;                   // safe given the semantics stated above
00530   }
00531   m_marshal_len = 0;
00532 }
00533 
00534 void
00535 LogFieldList::add(LogField *field, bool copy)
00536 {
00537   ink_assert(field != NULL);
00538 
00539   if (copy) {
00540     m_field_list.enqueue(new LogField(*field));
00541   } else {
00542     m_field_list.enqueue(field);
00543   }
00544 
00545   if (field->type() == LogField::sINT) {
00546     m_marshal_len += INK_MIN_ALIGN;
00547   }
00548 }
00549 
00550 LogField *
00551 LogFieldList::find_by_name(const char *name) const
00552 {
00553   for (LogField *f = first(); f; f = next(f)) {
00554     if (!strcmp(f->name(), name)) {
00555       return f;
00556     }
00557   }
00558   return NULL;
00559 }
00560 
00561 LogField *
00562 LogFieldList::find_by_symbol(const char *symbol) const
00563 {
00564   LogField *field = 0;
00565 
00566   if (Log::field_symbol_hash) {
00567     if (ink_hash_table_lookup(Log::field_symbol_hash, (char *) symbol, (InkHashTableValue *) & field) && field) {
00568       Debug("log-field-hash", "Field %s found", field->symbol());
00569       return field;
00570     }
00571   }
00572   // trusty old method
00573 
00574   for (field = first(); field; field = next(field)) {
00575     if (!strcmp(field->symbol(), symbol)) {
00576       return field;
00577     }
00578   }
00579 
00580   return NULL;
00581 }
00582 
00583 unsigned
00584 LogFieldList::marshal_len(LogAccess *lad)
00585 {
00586   int bytes = 0;
00587   for (LogField *f = first(); f; f = next(f)) {
00588     if (f->type() != LogField::sINT) {
00589       bytes += f->marshal_len(lad);
00590     }
00591   }
00592   return m_marshal_len + bytes;
00593 }
00594 
00595 unsigned
00596 LogFieldList::marshal(LogAccess *lad, char *buf)
00597 {
00598   char *ptr;
00599   int bytes = 0;
00600   for (LogField *f = first(); f; f = next(f)) {
00601     ptr = &buf[bytes];
00602     bytes += f->marshal(lad, ptr);
00603     ink_assert(bytes % INK_MIN_ALIGN == 0);
00604   }
00605   return bytes;
00606 }
00607 
00608 unsigned
00609 LogFieldList::marshal_agg(char *buf)
00610 {
00611   char *ptr;
00612   int bytes = 0;
00613   for (LogField *f = first(); f; f = next(f)) {
00614     ptr = &buf[bytes];
00615     bytes += f->marshal_agg(ptr);
00616   }
00617   return bytes;
00618 }
00619 
00620 unsigned
00621 LogFieldList::count()
00622 {
00623   unsigned cnt = 0;
00624   for (LogField *f = first(); f; f = next(f)) {
00625     cnt++;
00626   }
00627   return cnt;
00628 }
00629 
00630 void
00631 LogFieldList::display(FILE *fd)
00632 {
00633   for (LogField *f = first(); f; f = next(f)) {
00634     f->display(fd);
00635   }
00636 }

Generated by  doxygen 1.7.1