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

LogFormat.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  LogFormat.cc
00026 
00027 
00028  ***************************************************************************/
00029 #include "ink_config.h"
00030 
00031 #include <stdio.h>
00032 #include <string.h>
00033 #include <stdlib.h>
00034 
00035 #include "INK_MD5.h"
00036 
00037 #include "Error.h"
00038 #include "SimpleTokenizer.h"
00039 
00040 #include "LogUtils.h"
00041 #include "LogFile.h"
00042 #include "LogField.h"
00043 #include "LogFilter.h"
00044 #include "LogFormat.h"
00045 #include "LogHost.h"
00046 #include "LogBuffer.h"
00047 #include "LogObject.h"
00048 #include "LogConfig.h"
00049 #include "Log.h"
00050 
00051 // class variables
00052 //
00053 bool LogFormat::m_tagging_on = false;
00054 
00055 /*-------------------------------------------------------------------------
00056   LogFormat::setup
00057   -------------------------------------------------------------------------*/
00058 
00059 bool
00060 LogFormat::setup(const char *name, const char *format_str, unsigned interval_sec)
00061 {
00062   if (name == NULL) {
00063     Note("missing log format name");
00064     return false;
00065   }
00066 
00067   if (format_str) {
00068     const char *tag = " %<phn>";
00069     const size_t m_format_str_size = strlen(format_str) + (m_tagging_on ? strlen(tag) : 0) + 1;
00070     m_format_str = (char *)ats_malloc(m_format_str_size);
00071     ink_strlcpy(m_format_str, format_str, m_format_str_size);
00072     if (m_tagging_on) {
00073       Note("Log tagging enabled, adding %%<phn> field at the end of " "format %s", name);
00074       ink_strlcat(m_format_str, tag, m_format_str_size);
00075     };
00076 
00077     char *printf_str = NULL;
00078     char *fieldlist_str = NULL;
00079     int nfields = parse_format_string(m_format_str, &printf_str,
00080                                       &fieldlist_str);
00081     if (nfields > (m_tagging_on ? 1 : 0)) {
00082       init_variables(name, fieldlist_str, printf_str, interval_sec);
00083     } else {
00084       Note("Format %s encountered an error parsing the symbol string "
00085            "\"%s\", symbol string contains no fields", ((name) ? name : "no-name"), format_str);
00086       m_valid = false;
00087     }
00088 
00089     ats_free(fieldlist_str);
00090     ats_free(printf_str);
00091 
00092     // We are only valid if init_variables() says we are.
00093     return true;
00094   }
00095 
00096   // We don't have a format string (ie. this will be a raw text log, so we are always valid.
00097   m_valid = true;
00098   return true;
00099 }
00100 
00101 /*-------------------------------------------------------------------------
00102   LogFormat::id_from_name
00103   -------------------------------------------------------------------------*/
00104 
00105 int32_t LogFormat::id_from_name(const char *name)
00106 {
00107   int32_t id = 0;
00108   if (name) {
00109     CryptoHash hash;
00110     MD5Context().hash_immediate(hash, name, static_cast<int>(strlen(name)));
00111 #if defined(linux)
00112     /* Mask most signficant bit so that return value of this function
00113      * is not sign extended to be a negative number.
00114      * This problem is only known to occur on Linux which
00115      * is a 32-bit OS.
00116      */
00117     id = (int32_t) hash.fold() & 0x7fffffff;
00118 #else
00119     id = (int32_t) hash.fold();
00120 #endif
00121   }
00122   return id;
00123 }
00124 
00125 /*-------------------------------------------------------------------------
00126   LogFormat::init_variables
00127   -------------------------------------------------------------------------*/
00128 
00129 void
00130 LogFormat::init_variables(const char *name, const char *fieldlist_str, const char *printf_str, unsigned interval_sec)
00131 {
00132   m_field_count = parse_symbol_string(fieldlist_str, &m_field_list, &m_aggregate);
00133 
00134   if (m_field_count == 0) {
00135     m_valid = false;
00136   } else if (m_aggregate && !interval_sec) {
00137     Note("Format for aggregate operators but no interval " "was specified");
00138     m_valid = false;
00139   } else {
00140     if (m_aggregate) {
00141       m_agg_marshal_space = (char *)ats_malloc(m_field_count * INK_MIN_ALIGN);
00142     }
00143 
00144     if (m_name_str) {
00145       ats_free(m_name_str);
00146       m_name_str = NULL;
00147       m_name_id = 0;
00148     }
00149     if (name) {
00150       m_name_str = ats_strdup(name);
00151       m_name_id = id_from_name(m_name_str);
00152     }
00153 
00154     if (m_fieldlist_str) {
00155       ats_free(m_fieldlist_str);
00156       m_fieldlist_str = NULL;
00157       m_fieldlist_id = 0;
00158     }
00159     if (fieldlist_str) {
00160       m_fieldlist_str = ats_strdup(fieldlist_str);
00161       m_fieldlist_id = id_from_name(m_fieldlist_str);
00162     }
00163 
00164     m_printf_str = ats_strdup(printf_str);
00165     m_interval_sec = interval_sec;
00166     m_interval_next = LogUtils::timestamp();
00167 
00168     m_valid = true;
00169   }
00170 }
00171 
00172 /*-------------------------------------------------------------------------
00173   LogFormat::LogFormat
00174 
00175   This is the general ctor that builds a LogFormat object from the data
00176   provided.  In this case, the "fields" character string is a printf-style
00177   string where the field symbols are represented within the string in the
00178   form %<symbol>.
00179   -------------------------------------------------------------------------*/
00180 
00181 LogFormat::LogFormat(const char *name, const char *format_str, unsigned interval_sec)
00182   : m_interval_sec(0),
00183     m_interval_next(0),
00184     m_agg_marshal_space(NULL),
00185     m_valid(false),
00186     m_name_str(NULL),
00187     m_name_id(0),
00188     m_fieldlist_str(NULL),
00189     m_fieldlist_id(0),
00190     m_field_count(0),
00191     m_printf_str(NULL),
00192     m_aggregate(false),
00193     m_format_str(NULL)
00194 {
00195   setup(name, format_str, interval_sec);
00196 
00197   // A LOG_FORMAT_TEXT is a log without a format string, everything else is a LOG_FORMAT_CUSTOM. It's possible that we could get
00198   // rid of log types altogether, but LogFile currently tests whether a format is a LOG_FORMAT_TEXT format ...
00199   m_format_type = format_str ? LOG_FORMAT_CUSTOM : LOG_FORMAT_TEXT;
00200 }
00201 
00202 //-----------------------------------------------------------------------------
00203 // This constructor is used only in Log::match_logobject
00204 //
00205 // It is awkward because it does not take a format_str but a fieldlist_str
00206 // and a printf_str. These should be derived from a format_str but a
00207 // LogBufferHeader does not store the format_str, if it did, we could probably
00208 // delete this.
00209 //
00210 LogFormat::LogFormat(const char *name, const char *fieldlist_str, const char *printf_str, unsigned interval_sec)
00211   : m_interval_sec(0),
00212     m_interval_next(0),
00213     m_agg_marshal_space(NULL),
00214     m_valid(false),
00215     m_name_str(NULL),
00216     m_name_id(0),
00217     m_fieldlist_str(NULL),
00218     m_fieldlist_id(0),
00219     m_field_count(0),
00220     m_printf_str(NULL),
00221     m_aggregate(false),
00222     m_format_str(NULL)
00223 {
00224   init_variables(name, fieldlist_str, printf_str, interval_sec);
00225   m_format_type = LOG_FORMAT_CUSTOM;
00226 }
00227 
00228 /*-------------------------------------------------------------------------
00229   LogFormat::LogFormat
00230 
00231   This is the copy ctor, needed for copying lists of Format objects.
00232   -------------------------------------------------------------------------*/
00233 
00234 LogFormat::LogFormat(const LogFormat & rhs)
00235   : m_interval_sec(0),
00236     m_interval_next(0),
00237     m_agg_marshal_space(NULL),
00238     m_valid(rhs.m_valid),
00239     m_name_str(NULL),
00240     m_name_id(0),
00241     m_fieldlist_str(NULL),
00242     m_fieldlist_id(0),
00243     m_field_count(0),
00244     m_printf_str(NULL),
00245     m_aggregate(false),
00246     m_format_str(NULL),
00247     m_format_type(rhs.m_format_type)
00248 {
00249   if (m_valid) {
00250     if (m_format_type == LOG_FORMAT_TEXT) {
00251       m_name_str = ats_strdup(rhs.m_name_str);
00252     } else {
00253       m_format_str = rhs.m_format_str ? ats_strdup(rhs.m_format_str) : 0;
00254       init_variables(rhs.m_name_str, rhs.m_fieldlist_str, rhs.m_printf_str, rhs.m_interval_sec);
00255     }
00256   }
00257 }
00258 
00259 /*-------------------------------------------------------------------------
00260   LogFormat::~LogFormat
00261   -------------------------------------------------------------------------*/
00262 
00263 LogFormat::~LogFormat()
00264 {
00265   ats_free(m_name_str);
00266   ats_free(m_fieldlist_str);
00267   ats_free(m_printf_str);
00268   ats_free(m_agg_marshal_space);
00269   ats_free(m_format_str);
00270   m_valid = false;
00271 }
00272 
00273 /*-------------------------------------------------------------------------
00274   LogFormat::format_from_specification
00275 
00276   This routine is obsolete as of 3.1, but will be kept around to preserve
00277   the old log config file option.
00278 
00279   This (static) function examines the given log format specification string
00280   and builds a new LogFormat object if the format specification is valid.
00281   On success, a pointer to a LogFormat object allocated from the heap (with
00282   new) will be returned.  On error, NULL is returned.
00283   -------------------------------------------------------------------------*/
00284 
00285 LogFormat *
00286 LogFormat::format_from_specification(char *spec, char **file_name, char **file_header, LogFileFormat * file_type)
00287 {
00288   LogFormat *format;
00289   char *token;
00290   int format_id;
00291   char *format_name, *format_str;
00292 
00293   ink_assert(file_name != NULL);
00294   ink_assert(file_header != NULL);
00295   ink_assert(file_type != NULL);
00296 
00297   SimpleTokenizer tok(spec, ':');
00298 
00299   //
00300   // Divide the specification string into tokens using the ':' as a
00301   // field separator.  There are currently eight (8) tokens that comprise
00302   // a format specification.  Verify each of the token values and if
00303   // everything looks ok, then build the LogFormat object.
00304   //
00305   // First should be the "format" keyword that says this is a format spec.
00306   //
00307   token = tok.getNext();
00308   if (token == NULL) {
00309     Debug("log-format", "token expected");
00310     return NULL;
00311   }
00312   if (strcasecmp(token, "format") == 0) {
00313     Debug("log-format", "this is a format");
00314   } else {
00315     Debug("log-format", "should be 'format'");
00316     return NULL;
00317   }
00318 
00319   //
00320   // Next should be the word "enabled" or "disabled", which indicates
00321   // whether we should care about this format or not.
00322   //
00323   token = tok.getNext();
00324   if (token == NULL) {
00325     Debug("log-format", "token expected");
00326     return NULL;
00327   }
00328   if (!strcasecmp(token, "disabled")) {
00329     Debug("log-format", "format not enabled, skipping ...");
00330     return NULL;
00331   } else if (!strcasecmp(token, "enabled")) {
00332     Debug("log-format", "enabled format");
00333   } else {
00334     Debug("log-format", "should be 'enabled' or 'disabled', not %s", token);
00335     return NULL;
00336   }
00337 
00338   //
00339   // Next should be the numeric format identifier
00340   //
00341   token = tok.getNext();
00342   if (token == NULL) {
00343     Debug("log-format", "token expected");
00344     return NULL;
00345   }
00346   format_id = atoi(token);
00347   // NOW UNUSED !!!
00348 
00349   //
00350   // Next should be the format name
00351   //
00352   token = tok.getNext();
00353   if (token == NULL) {
00354     Debug("log-format", "token expected");
00355     return NULL;
00356   }
00357   format_name = token;
00358 
00359   //
00360   // Next should be the printf-stlye format symbol string
00361   //
00362   token = tok.getNext();
00363   if (token == NULL) {
00364     Debug("log-format", "token expected");
00365     return NULL;
00366   }
00367   format_str = token;
00368 
00369   //
00370   // Next should be the file name for the log
00371   //
00372   token = tok.getNext();
00373   if (token == NULL) {
00374     Debug("log-format", "token expected");
00375     return NULL;
00376   }
00377   *file_name = ats_strdup(token);
00378 
00379   //
00380   // Next should be the file type, either "ASCII" or "BINARY"
00381   //
00382   token = tok.getNext();
00383   if (token == NULL) {
00384     Debug("log-format", "token expected");
00385     return NULL;
00386   }
00387   if (!strcasecmp(token, "ASCII")) {
00388     *file_type = LOG_FILE_ASCII;
00389   } else if (!strcasecmp(token, "BINARY")) {
00390     *file_type = LOG_FILE_BINARY;
00391   } else {
00392     Debug("log-format", "%s is not a valid file format (ASCII or BINARY)", token);
00393     return NULL;
00394   }
00395 
00396   //
00397   // the rest should be the file header
00398   //
00399   token = tok.getRest();
00400   if (token == NULL) {
00401     Debug("log-format", "token expected");
00402     return NULL;
00403   }
00404   // set header to NULL if "none" was specified (a NULL header means
00405   // "write no header" to the rest of the logging system)
00406   //
00407   *file_header = strcmp(token, "none") == 0 ? NULL : ats_strdup(token);
00408 
00409   Debug("log-format", "custom:%d:%s:%s:%s:%d:%s", format_id, format_name, format_str, *file_name, *file_type, token);
00410 
00411   format = new LogFormat(format_name, format_str);
00412   ink_assert(format != NULL);
00413   if (!format->valid()) {
00414     delete format;
00415     return NULL;
00416   }
00417 
00418   return format;
00419 }
00420 
00421 /*-------------------------------------------------------------------------
00422   LogFormat::parse_symbol_string
00423 
00424   This function does the work of parsing a comma-separated symbol list and
00425   adding them to the LogFieldList that is provided.  The total number of
00426   fields added to the list is returned.
00427   -------------------------------------------------------------------------*/
00428 
00429 int
00430 LogFormat::parse_symbol_string(const char *symbol_string, LogFieldList *field_list, bool *contains_aggregates)
00431 {
00432   char *sym_str;
00433   int field_count = 0;
00434   LogField *f;
00435   char *symbol, *name, *sym;
00436   LogField::Container container;
00437   LogField::Aggregate aggregate;
00438 
00439   if (symbol_string == NULL)
00440     return 0;
00441   ink_assert(field_list != NULL);
00442   ink_assert(contains_aggregates != NULL);
00443 
00444   *contains_aggregates = false; // we'll change if it does
00445 
00446   //
00447   // strtok will mangle the input string; we'll make a copy for that.
00448   //
00449   sym_str = ats_strdup(symbol_string);
00450   symbol = strtok(sym_str, ",");
00451 
00452   while (symbol != NULL) {
00453     //
00454     // See if there is an aggregate operator, which will contain "()"
00455     //
00456     char *begin_paren = strchr(symbol, '(');
00457     if (begin_paren) {
00458       char *end_paren = strchr(symbol, ')');
00459       if (end_paren) {
00460         Debug("log-agg", "Aggregate symbol: %s", symbol);
00461         *begin_paren = '\0';
00462         *end_paren = '\0';
00463         name = begin_paren + 1;
00464         sym = symbol;
00465         Debug("log-agg", "Aggregate = %s, field = %s", sym, name);
00466         aggregate = LogField::valid_aggregate_name(sym);
00467         if (aggregate == LogField::NO_AGGREGATE) {
00468           Note("Invalid aggregate specification: %s", sym);
00469         } else {
00470           if (aggregate == LogField::eCOUNT && strcmp(name, "*") == 0) {
00471             f = Log::global_field_list.find_by_symbol("psql");
00472           } else {
00473             f = Log::global_field_list.find_by_symbol(name);
00474           }
00475           if (!f) {
00476             Note("Invalid field symbol %s used in aggregate " "operation", name);
00477           } else if (f->type() != LogField::sINT) {
00478             Note("Only single integer field types may be aggregated");
00479           } else {
00480             LogField *new_f = new LogField(*f);
00481             new_f->set_aggregate_op(aggregate);
00482             field_list->add(new_f, false);
00483             field_count++;
00484             *contains_aggregates = true;
00485             Debug("log-agg", "Aggregate field %s(%s) added", sym, name);
00486           }
00487         }
00488       } else {
00489         Note("Invalid aggregate field specification: no trailing " "')' in %s", symbol);
00490       }
00491     }
00492     //
00493     // Now check for a container field, which starts with '{'
00494     //
00495     else if (*symbol == '{') {
00496       Debug("log-format", "Container symbol: %s", symbol);
00497       f = NULL;
00498       char *name_end = strchr(symbol, '}');
00499       if (name_end != NULL) {
00500         name = symbol + 1;
00501         *name_end = 0;          // changes '}' to '\0'
00502         sym = name_end + 1;     // start of container symbol
00503         LogSlice slice(sym);
00504         Debug("log-format", "Name = %s, symbol = %s", name, sym);
00505         container = LogField::valid_container_name(sym);
00506         if (container == LogField::NO_CONTAINER) {
00507           Note("Invalid container specification: %s", sym);
00508         } else {
00509           f = new LogField(name, container);
00510           ink_assert(f != NULL);
00511           if (slice.m_enable) {
00512             f->m_slice = slice;
00513             Debug("log-slice", "symbol = %s, [%d:%d]", sym,
00514                   f->m_slice.m_start, f->m_slice.m_end);
00515           }
00516           field_list->add(f, false);
00517           field_count++;
00518           Debug("log-format", "Container field {%s}%s added", name, sym);
00519         }
00520       } else {
00521         Note("Invalid container field specification: no trailing " "'}' in %s", symbol);
00522       }
00523     }
00524     //
00525     // treat this like a regular field symbol
00526     //
00527     else {
00528       LogSlice slice(symbol);
00529       Debug("log-format", "Regular field symbol: %s", symbol);
00530       f = Log::global_field_list.find_by_symbol(symbol);
00531       if (f != NULL) {
00532         LogField *cpy = new LogField(*f);
00533         if (slice.m_enable) {
00534           cpy->m_slice = slice;
00535           Debug("log-slice", "symbol = %s, [%d:%d]", symbol,
00536                 cpy->m_slice.m_start, cpy->m_slice.m_end);
00537         }
00538         field_list->add(cpy, false);
00539         field_count++;
00540         Debug("log-format", "Regular field %s added", symbol);
00541       } else {
00542         Note("The log format symbol %s was not found in the " "list of known symbols.", symbol);
00543       }
00544     }
00545 
00546     //
00547     // Get the next symbol
00548     //
00549     symbol = strtok(NULL, ",");
00550   }
00551 
00552   ats_free(sym_str);
00553   return field_count;
00554 }
00555 
00556 //
00557 // Parse escape string, supports two forms:
00558 //
00559 // 1) Octal representation: '\abc', for example: '\060'
00560 //    0 < (a*8^2 + b*8 + c) < 255
00561 //
00562 // 2) Hex representation: '\xab', for exampe: '\x3A'
00563 //    0 < (a*16 + b) < 255
00564 //
00565 // Return -1 if the beginning four characters are not valid
00566 // escape sequence, otherwise reutrn unsigned char value of the
00567 // escape sequence in the string.
00568 //
00569 // NOTE: The value of escape sequence should be greater than 0
00570 //       and less than 255, since:
00571 //       - 0 is terminator of string, and
00572 //       - 255('\377') has been used as LOG_FIELD_MARKER.
00573 //
00574 int
00575 LogFormat::parse_escape_string(const char *str, int len)
00576 {
00577   int sum, start = 0;
00578   unsigned char a, b, c;
00579 
00580   if (str[start] != '\\' || len < 2)
00581     return -1;
00582 
00583   if (str[start + 1] == '\\')
00584     return '\\';
00585 
00586   if (len < 4)
00587     return -1;
00588 
00589   a = (unsigned char)str[start + 1];
00590   b = (unsigned char)str[start + 2];
00591   c = (unsigned char)str[start + 3];
00592 
00593   if (isdigit(a) && isdigit(b) && isdigit(b)) {
00594 
00595     sum = (a - '0')*64 + (b - '0')*8 + (c - '0');
00596 
00597     if (sum == 0 || sum >= 255) {
00598       Warning("Octal escape sequence out of range: \\%c%c%c, treat it as normal string\n", a, b, c);
00599       return -1;
00600     } else
00601       return sum;
00602 
00603   } else if (tolower(a) == 'x' && isxdigit(b) && isxdigit(c)) {
00604     int i, j;
00605     if (isdigit(b))
00606       i = b - '0';
00607     else
00608       i = toupper(b) - 'A' + 10;
00609 
00610     if (isdigit(c))
00611       j = c - '0';
00612     else
00613       j = toupper(c) - 'A' + 10;
00614 
00615     sum = i*16 + j;
00616 
00617     if (sum == 0 || sum >= 255) {
00618       Warning("Hex escape sequence out of range: \\%c%c%c, treat it as normal string\n", a, b, c);
00619       return -1;
00620     } else
00621       return sum;
00622   }
00623 
00624   return -1;
00625 }
00626 
00627 /*-------------------------------------------------------------------------
00628   LogFormat::parse_format_string
00629 
00630   This function will parse a custom log format string, which is a
00631   combination of printf characters and logging field names, separating this
00632   combined format string into a normal printf string and a fieldlist.  The
00633   number of logging fields parsed will be returned.  The two strings
00634   returned are allocated with ats_malloc, and should be released by the
00635   caller.  The function returns -1 on error.
00636 
00637   For 3.1, I've added the ability to log summary information using
00638   aggregate operators SUM, COUNT, AVG, ...
00639   -------------------------------------------------------------------------*/
00640 
00641 int
00642 LogFormat::parse_format_string(const char *format_str, char **printf_str, char **fields_str)
00643 {
00644   ink_assert(printf_str != NULL);
00645   ink_assert(fields_str != NULL);
00646 
00647   if (format_str == NULL) {
00648     *printf_str = *fields_str = NULL;
00649     return 0;
00650   }
00651   //
00652   // Since the given format string is a combination of the printf-string
00653   // and the field symbols, when we break it up into these two components
00654   // each is guaranteed to be smaller (or the same size) as the format
00655   // string.
00656   //
00657   unsigned len = (unsigned)::strlen(format_str);
00658   *printf_str = (char *)ats_malloc(len + 1);
00659   *fields_str = (char *)ats_malloc(len + 1);
00660 
00661   unsigned printf_pos = 0;
00662   unsigned fields_pos = 0;
00663   unsigned field_count = 0;
00664   unsigned field_len;
00665   unsigned start, stop;
00666   int escape_char;
00667 
00668   for (start = 0; start < len; start++) {
00669     //
00670     // Look for logging fields: %<field>
00671     //
00672     if ((format_str[start] == '%') && (start + 1 < len) && (format_str[start + 1] == '<')) {
00673       //
00674       // this is a field symbol designation; look for the
00675       // trailing '>'.
00676       //
00677       if (fields_pos > 0) {
00678         (*fields_str)[fields_pos++] = ',';
00679       }
00680       for (stop = start + 2; stop < len; stop++) {
00681         if (format_str[stop] == '>') {
00682           break;
00683         }
00684       }
00685       if (format_str[stop] == '>') {
00686         //
00687         // We found the termination for this field spec;
00688         // copy the field symbol to the symbol string and place a
00689         // LOG_FIELD_MARKER in the printf string.
00690         //
00691         field_len = stop - start - 2;
00692         memcpy(&(*fields_str)[fields_pos], &format_str[start + 2], field_len);
00693         fields_pos += field_len;
00694         (*printf_str)[printf_pos++] = LOG_FIELD_MARKER;
00695         ++field_count;
00696         start = stop;
00697       } else {
00698         //
00699         // This was not a logging field spec after all,
00700         // then try to detect and parse escape string.
00701         //
00702         escape_char = parse_escape_string(&format_str[start], (len - start));
00703 
00704         if (escape_char == '\\') {
00705           start += 1;
00706           (*printf_str)[printf_pos++] = (char)escape_char;
00707         } else if (escape_char >= 0) {
00708           start += 3;
00709           (*printf_str)[printf_pos++] = (char)escape_char;
00710         } else {
00711           memcpy(&(*printf_str)[printf_pos], &format_str[start], stop - start + 1);
00712           printf_pos += stop - start + 1;
00713         }
00714       }
00715     } else {
00716       //
00717       // This was not the start of a logging field spec,
00718       // then try to detect and parse escape string.
00719       //
00720       escape_char = parse_escape_string(&format_str[start], (len - start));
00721 
00722       if (escape_char == '\\') {
00723         start += 1;
00724         (*printf_str)[printf_pos++] = (char)escape_char;
00725       } else if (escape_char >= 0) {
00726         start += 3;
00727         (*printf_str)[printf_pos++] = (char)escape_char;
00728       } else {
00729         (*printf_str)[printf_pos++] = format_str[start];
00730       }
00731     }
00732   }
00733 
00734   //
00735   // Ok, now NULL terminate the strings and return the number of fields
00736   // actually found.
00737   //
00738   (*fields_str)[fields_pos] = '\0';
00739   (*printf_str)[printf_pos] = '\0';
00740 
00741   Debug("log-format", "LogFormat::parse_format_string: field_count=%d, \"%s\", \"%s\"", field_count, *fields_str,
00742         *printf_str);
00743   return field_count;
00744 }
00745 
00746 /*-------------------------------------------------------------------------
00747   LogFormat::display
00748 
00749   Print out some info about this object.
00750   -------------------------------------------------------------------------*/
00751 
00752 void
00753 LogFormat::display(FILE * fd)
00754 {
00755   static const char *types[] = {
00756     "SQUID_LOG",
00757     "COMMON_LOG",
00758     "EXTENDED_LOG",
00759     "EXTENDED2_LOG",
00760     "LOG_FORMAT_CUSTOM",
00761     "LOG_FORMAT_TEXT"
00762   };
00763 
00764   fprintf(fd, "--------------------------------------------------------\n");
00765   fprintf(fd, "Format : %s (%s) (%p), %u fields.\n", m_name_str, types[m_format_type], this, m_field_count);
00766   if (m_fieldlist_str) {
00767     fprintf(fd, "Symbols: %s\n", m_fieldlist_str);
00768     fprintf(fd, "Fields :\n");
00769     m_field_list.display(fd);
00770   } else {
00771     fprintf(fd, "Fields : None\n");
00772   }
00773   fprintf(fd, "--------------------------------------------------------\n");
00774 }
00775 
00776 void
00777 LogFormat::displayAsXML(FILE * fd)
00778 {
00779   if (valid()) {
00780     fprintf(fd,
00781             "<LogFormat>\n"
00782             "  <Name     = \"%s\"/>\n"
00783             "  <Format   = \"%s\"/>\n"
00784             "  <Interval = \"%ld\"/>\n" "</LogFormat>\n", m_name_str, m_format_str, m_interval_sec);
00785   } else {
00786     fprintf(fd, "INVALID FORMAT\n");
00787   }
00788 }
00789 
00790 /*-------------------------------------------------------------------------
00791   LogFormatList
00792   -------------------------------------------------------------------------*/
00793 
00794 LogFormatList::LogFormatList()
00795 {
00796 }
00797 
00798 LogFormatList::~LogFormatList()
00799 {
00800   clear();
00801 }
00802 
00803 void
00804 LogFormatList::clear()
00805 {
00806   LogFormat *f;
00807   while ((f = m_format_list.dequeue())) {
00808     delete f;
00809   }
00810 }
00811 
00812 void
00813 LogFormatList::add(LogFormat * format, bool copy)
00814 {
00815   ink_assert(format != NULL);
00816 
00817   if (copy) {
00818     m_format_list.enqueue(new LogFormat(*format));
00819   } else {
00820     m_format_list.enqueue(format);
00821   }
00822 }
00823 
00824 LogFormat *
00825 LogFormatList::find_by_name(const char *name) const
00826 {
00827   for (LogFormat * f = first(); f; f = next(f)) {
00828     if (!strcmp(f->name(), name)) {
00829       return f;
00830     }
00831   }
00832   return NULL;
00833 }
00834 
00835 unsigned
00836 LogFormatList::count()
00837 {
00838   unsigned cnt = 0;
00839   for (LogFormat * f = first(); f; f = next(f)) {
00840     cnt++;
00841   }
00842   return cnt;
00843 }
00844 
00845 void
00846 LogFormatList::display(FILE * fd)
00847 {
00848   for (LogFormat * f = first(); f; f = next(f)) {
00849     f->display(fd);
00850   }
00851 }

Generated by  doxygen 1.7.1