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

Diags.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 
00026   Diags.cc
00027 
00028   This file contains code to manipulate run-time diagnostics, and print
00029   warnings and errors at runtime.  Action tags and debugging tags are
00030   supported, allowing run-time conditionals affecting diagnostics.
00031 
00032   Joe User should only need to use the macros at the bottom of Diags.h
00033 
00034 
00035  ****************************************************************************/
00036 
00037 #include "ink_platform.h"
00038 #include "ink_memory.h"
00039 #include "ink_defs.h"
00040 #include "ink_error.h"
00041 #include "ink_assert.h"
00042 #include "ink_time.h"
00043 #include "ink_hrtime.h"
00044 #include "Diags.h"
00045 #include "Compatability.h"
00046 
00047 
00048 int diags_on_for_plugins = 0;
00049 bool DiagsConfigState::enabled[2] = { false, false };
00050 
00051 // Global, used for all diagnostics
00052 inkcoreapi Diags *diags = NULL;
00053 
00054 //////////////////////////////////////////////////////////////////////////////
00055 //
00056 //      char *SrcLoc::str(char *buf, int buflen)
00057 //
00058 //      This method takes a SrcLoc source location data structure and
00059 //      converts it to a human-readable representation, in the buffer <buf>
00060 //      with length <buflen>.  The buffer will always be NUL-terminated, and
00061 //      must always have a length of at least 1.  The buffer address is
00062 //      returned on success.  The routine will only fail if the SrcLoc is
00063 //      not valid, or the buflen is less than 1.
00064 //
00065 //////////////////////////////////////////////////////////////////////////////
00066 
00067 char *
00068 SrcLoc::str(char *buf, int buflen) const
00069 {
00070   const char * shortname;
00071 
00072   if (!this->valid() || buflen < 1)
00073     return (NULL);
00074 
00075   shortname = strrchr(file, '/');
00076   shortname = shortname ? (shortname + 1) : file;
00077 
00078   if (func != NULL) {
00079     snprintf(buf, buflen, "%s:%d (%s)", shortname, line, func);
00080   } else {
00081     snprintf(buf, buflen, "%s:%d", shortname, line);
00082   }
00083   buf[buflen - 1] = NUL;
00084   return (buf);
00085 }
00086 
00087 
00088 
00089 
00090 //////////////////////////////////////////////////////////////////////////////
00091 //
00092 //      Diags::Diags(char *bdt, char *bat)
00093 //
00094 //      This is the constructor for the Diags class.  The constructor takes
00095 //      two strings called the "base debug tags" (bdt) and the
00096 //      "base action tags" (bat).  These represent debug/action overrides,
00097 //      to override the records.config values.  They current come from
00098 //      command-line options.
00099 //
00100 //      If bdt is not NULL, and not "", it overrides records.config settings.
00101 //      If bat is not NULL, and not "", it overrides records.config settings.
00102 //
00103 //      When the constructor is done, records.config callbacks will be set,
00104 //      the initial values read, and the Diags instance will be ready to use.
00105 //
00106 //////////////////////////////////////////////////////////////////////////////
00107 
00108 Diags::Diags(const char *bdt, const char *bat, FILE * _diags_log_fp)
00109   : diags_log_fp(_diags_log_fp), magic(DIAGS_MAGIC), show_location(0),
00110     base_debug_tags(NULL), base_action_tags(NULL)
00111 {
00112   int i;
00113 
00114   cleanup_func = NULL;
00115   ink_mutex_init(&tag_table_lock, "Diags::tag_table_lock");
00116 
00117   ////////////////////////////////////////////////////////
00118   // initialize the default, base debugging/action tags //
00119   ////////////////////////////////////////////////////////
00120 
00121   if (bdt && *bdt) {
00122     base_debug_tags = ats_strdup(bdt);
00123   }
00124   if (bat && *bat) {
00125     base_action_tags = ats_strdup(bat);
00126   }
00127 
00128   config.enabled[DiagsTagType_Debug] = (base_debug_tags != NULL);
00129   config.enabled[DiagsTagType_Action] = (base_action_tags != NULL);
00130   diags_on_for_plugins = config.enabled[DiagsTagType_Debug];
00131 
00132   for (i = 0; i < DiagsLevel_Count; i++) {
00133     config.outputs[i].to_stdout = false;
00134     config.outputs[i].to_stderr = false;
00135     config.outputs[i].to_syslog = false;
00136     config.outputs[i].to_diagslog = true;
00137   }
00138 
00139   //////////////////////////////////////////////////////////////////
00140   // start off with empty tag tables, will build in reconfigure() //
00141   //////////////////////////////////////////////////////////////////
00142 
00143   activated_tags[DiagsTagType_Debug] = NULL;
00144   activated_tags[DiagsTagType_Action] = NULL;
00145   prefix_str = "";
00146 
00147 }
00148 
00149 Diags::~Diags()
00150 {
00151   diags_log_fp = NULL;
00152 
00153   ats_free((void *)base_debug_tags);
00154   ats_free((void *)base_action_tags);
00155 
00156   deactivate_all(DiagsTagType_Debug);
00157   deactivate_all(DiagsTagType_Action);
00158 }
00159 
00160 
00161 //////////////////////////////////////////////////////////////////////////////
00162 //
00163 //      void Diags::print_va(...)
00164 //
00165 //      This is the lowest-level diagnostic printing routine, that does the
00166 //      work of formatting and outputting diagnostic and error messages,
00167 //      in the standard format.
00168 //
00169 //      This routine takes an optional <debug_tag>, which is printed in
00170 //      parentheses if its value is not NULL.  It takes a <diags_level>,
00171 //      which is converted to a prefix string.
00172 //      print_va takes an optional source location structure pointer <loc>,
00173 //      which can be NULL.  If <loc> is not NULL, the source code location
00174 //      is converted to a string, and printed between angle brackets.
00175 //      Finally, it takes a printf format string <format_string>, and a
00176 //      va_list list of varargs.
00177 //
00178 //      This routine outputs to all of the output targets enabled for this
00179 //      debugging level in config.outputs[diags_level].  Many higher level
00180 //      diagnosting printing routines are built upon print_va, including:
00181 //
00182 //              void print(...)
00183 //              void log_va(...)
00184 //              void log(...)
00185 //
00186 //////////////////////////////////////////////////////////////////////////////
00187 
00188 void
00189 Diags::print_va(const char *debug_tag, DiagsLevel diags_level, const SrcLoc *loc,
00190                 const char *format_string, va_list ap) const
00191 {
00192   struct timeval tp;
00193   const char *s;
00194   char *buffer, *d, timestamp_buf[48];
00195   char format_buf[1024], format_buf_w_ts[1024], *end_of_format;
00196 
00197   ////////////////////////////////////////////////////////////////////////
00198   // there are 2 format buffers that hold a printf-style format string  //
00199   // format_buf contains <prefix_string>: (<debug_tag>) <format_string> //
00200   // and format_buf_w_ts has the same thing with a prepended timestamp. //
00201   ////////////////////////////////////////////////////////////////////////
00202 
00203   format_buf[0] = NUL;
00204   format_buf_w_ts[0] = NUL;
00205 
00206   /////////////////////////////////////////////////////
00207   // format_buf holds 1024 characters, end_of_format //
00208   // points to the current available character       //
00209   /////////////////////////////////////////////////////
00210 
00211   end_of_format = format_buf;
00212   *end_of_format = NUL;
00213 
00214   // add the thread id
00215   pthread_t id = pthread_self();
00216   end_of_format += snprintf(end_of_format, sizeof(format_buf), "{0x%" PRIx64 "} ", (uint64_t) id);
00217 
00218   //////////////////////////////////////
00219   // start with the diag level prefix //
00220   //////////////////////////////////////
00221 
00222   for (s = level_name(diags_level); *s; *end_of_format++ = *s++);
00223   *end_of_format++ = ':';
00224   *end_of_format++ = ' ';
00225 
00226   /////////////////////////////
00227   // append location, if any //
00228   /////////////////////////////
00229 
00230   if (loc && loc->valid()) {
00231     char *lp, buf[256];
00232     lp = loc->str(buf, sizeof(buf));
00233     if (lp) {
00234       *end_of_format++ = '<';
00235       for (s = lp; *s; *end_of_format++ = *s++);
00236       *end_of_format++ = '>';
00237       *end_of_format++ = ' ';
00238     }
00239   }
00240   //////////////////////////
00241   // append debugging tag //
00242   //////////////////////////
00243 
00244   if (debug_tag) {
00245     *end_of_format++ = '(';
00246     for (s = debug_tag; *s; *end_of_format++ = *s++);
00247     *end_of_format++ = ')';
00248     *end_of_format++ = ' ';
00249   }
00250   //////////////////////////////////////////////////////
00251   // append original format string, and NUL terminate //
00252   //////////////////////////////////////////////////////
00253 
00254   for (s = format_string; *s; *end_of_format++ = *s++);
00255   *end_of_format++ = NUL;
00256 
00257 
00258   //////////////////////////////////////////////////////////////////
00259   // prepend timestamp into the timestamped version of the buffer //
00260   //////////////////////////////////////////////////////////////////
00261 
00262   ink_gethrtimeofday(&tp, NULL);
00263   time_t cur_clock = (time_t) tp.tv_sec;
00264   buffer = ink_ctime_r(&cur_clock, timestamp_buf);
00265   snprintf(&(timestamp_buf[19]), (sizeof(timestamp_buf) - 20), ".%03d", (int) (tp.tv_usec / 1000));
00266 
00267   d = format_buf_w_ts;
00268   *d++ = '[';
00269   for (int i = 4; buffer[i]; i++)
00270     *d++ = buffer[i];
00271   *d++ = ']';
00272   *d++ = ' ';
00273 
00274   for (int k = 0; prefix_str[k]; k++)
00275     *d++ = prefix_str[k];
00276   for (s = format_buf; *s; *d++ = *s++);
00277   *d++ = NUL;
00278 
00279   //////////////////////////////////////
00280   // now, finally, output the message //
00281   //////////////////////////////////////
00282 
00283   lock();
00284   if (config.outputs[diags_level].to_diagslog) {
00285     if (diags_log_fp) {
00286       va_list ap_scratch;
00287       va_copy(ap_scratch, ap);
00288       buffer = format_buf_w_ts;
00289       vfprintf(diags_log_fp, buffer, ap_scratch);
00290       {
00291         int len = strlen(buffer);
00292         if (len > 0 && buffer[len - 1] != '\n') {
00293           putc('\n', diags_log_fp);
00294         }
00295       }
00296     }
00297   }
00298 
00299   if (config.outputs[diags_level].to_stdout) {
00300     va_list ap_scratch;
00301     va_copy(ap_scratch, ap);
00302     buffer = format_buf_w_ts;
00303     vfprintf(stdout, buffer, ap_scratch);
00304     {
00305       int len = strlen(buffer);
00306       if (len > 0 && buffer[len - 1] != '\n') {
00307         putc('\n', stdout);
00308       }
00309     }
00310   }
00311 
00312   if (config.outputs[diags_level].to_stderr) {
00313     va_list ap_scratch;
00314     va_copy(ap_scratch, ap);
00315     buffer = format_buf_w_ts;
00316     vfprintf(stderr, buffer, ap_scratch);
00317     {
00318       int len = strlen(buffer);
00319       if (len > 0 && buffer[len - 1] != '\n') {
00320         putc('\n', stderr);
00321       }
00322     }
00323   }
00324 
00325 #if !defined(freebsd)
00326   unlock();
00327 #endif
00328 
00329   if (config.outputs[diags_level].to_syslog) {
00330     int priority;
00331     char syslog_buffer[2048];
00332 
00333     switch (diags_level) {
00334     case DL_Diag:
00335     case DL_Debug:
00336       priority = LOG_DEBUG;
00337 
00338       break;
00339     case DL_Status:
00340       priority = LOG_INFO;
00341       break;
00342     case DL_Note:
00343       priority = LOG_NOTICE;
00344       break;
00345     case DL_Warning:
00346       priority = LOG_WARNING;
00347       break;
00348     case DL_Error:
00349       priority = LOG_ERR;
00350       break;
00351     case DL_Fatal:
00352       priority = LOG_CRIT;
00353       break;
00354     case DL_Alert:
00355       priority = LOG_ALERT;
00356       break;
00357     case DL_Emergency:
00358       priority = LOG_EMERG;
00359       break;
00360     default:
00361       priority = LOG_NOTICE;
00362       break;
00363     }
00364     vsnprintf(syslog_buffer, sizeof(syslog_buffer) - 1, format_buf, ap);
00365     syslog(priority, "%s", syslog_buffer);
00366   }
00367 #if defined(freebsd)
00368   unlock();
00369 #endif
00370 }
00371 
00372 
00373 //////////////////////////////////////////////////////////////////////////////
00374 //
00375 //      bool Diags::tag_activated(char * tag, DiagsTagType mode)
00376 //
00377 //      This routine inquires if a particular <tag> in the tag table of
00378 //      type <mode> is activated, returning true if it is, false if it
00379 //      isn't.  If <tag> is NULL, true is returned.  The call uses a lock
00380 //      to get atomic access to the tag tables.
00381 //
00382 //////////////////////////////////////////////////////////////////////////////
00383 
00384 bool
00385 Diags::tag_activated(const char *tag, DiagsTagType mode) const
00386 {
00387   bool activated = false;
00388 
00389   if (tag == NULL)
00390     return (true);
00391 
00392   lock();
00393   if (activated_tags[mode])
00394     activated = (activated_tags[mode]->match(tag) != -1);
00395   unlock();
00396 
00397   return (activated);
00398 }
00399 
00400 
00401 //////////////////////////////////////////////////////////////////////////////
00402 //
00403 //      void Diags::activate_taglist(char * taglist, DiagsTagType mode)
00404 //
00405 //      This routine adds all tags in the vertical-bar-seperated taglist
00406 //      to the tag table of type <mode>.  Each addition is done under a lock.
00407 //      If an individual tag is already set, that tag is ignored.  If
00408 //      <taglist> is NULL, this routine exits immediately.
00409 //
00410 //////////////////////////////////////////////////////////////////////////////
00411 
00412 void
00413 Diags::activate_taglist(const char *taglist, DiagsTagType mode)
00414 {
00415   if (taglist) {
00416     lock();
00417     if (activated_tags[mode]) {
00418       delete activated_tags[mode];
00419     }
00420     activated_tags[mode] = new DFA;
00421     activated_tags[mode]->compile(taglist);
00422     unlock();
00423   }
00424 }
00425 
00426 
00427 //////////////////////////////////////////////////////////////////////////////
00428 //
00429 //      void Diags::deactivate_all(DiagsTagType mode)
00430 //
00431 //      This routine deactivates all tags in the tag table of type <mode>.
00432 //      The deactivation is done under a lock.  When done, the taglist will
00433 //      be empty.
00434 //
00435 //////////////////////////////////////////////////////////////////////////////
00436 
00437 void
00438 Diags::deactivate_all(DiagsTagType mode)
00439 {
00440   lock();
00441   if (activated_tags[mode]) {
00442     delete activated_tags[mode];
00443     activated_tags[mode] = NULL;
00444   }
00445   unlock();
00446 }
00447 
00448 
00449 //////////////////////////////////////////////////////////////////////////////
00450 //
00451 //      const char *Diags::level_name(DiagsLevel dl)
00452 //
00453 //      This routine returns a string name corresponding to the error
00454 //      level <dl>, suitable for us as an output log entry prefix.
00455 //
00456 //////////////////////////////////////////////////////////////////////////////
00457 
00458 const char *
00459 Diags::level_name(DiagsLevel dl) const
00460 {
00461   switch (dl) {
00462   case DL_Diag:
00463     return ("DIAG");
00464   case DL_Debug:
00465     return ("DEBUG");
00466   case DL_Status:
00467     return ("STATUS");
00468   case DL_Note:
00469     return ("NOTE");
00470   case DL_Warning:
00471     return ("WARNING");
00472   case DL_Error:
00473     return ("ERROR");
00474   case DL_Fatal:
00475     return ("FATAL");
00476   case DL_Alert:
00477     return ("ALERT");
00478   case DL_Emergency:
00479     return ("EMERGENCY");
00480   default:
00481     return ("DIAG");
00482   }
00483 }
00484 
00485 
00486 //////////////////////////////////////////////////////////////////////////////
00487 //
00488 //      void Diags::dump(FILE *fp)
00489 //
00490 //////////////////////////////////////////////////////////////////////////////
00491 
00492 void
00493 Diags::dump(FILE * fp) const
00494 {
00495   int i;
00496 
00497   fprintf(fp, "Diags:\n");
00498   fprintf(fp, "  debug.enabled: %d\n", config.enabled[DiagsTagType_Debug]);
00499   fprintf(fp, "  debug default tags: '%s'\n", (base_debug_tags ? base_debug_tags : "NULL"));
00500   fprintf(fp, "  action.enabled: %d\n", config.enabled[DiagsTagType_Action]);
00501   fprintf(fp, "  action default tags: '%s'\n", (base_action_tags ? base_action_tags : "NULL"));
00502   fprintf(fp, "  outputs:\n");
00503   for (i = 0; i < DiagsLevel_Count; i++) {
00504     fprintf(fp, "    %10s [stdout=%d, stderr=%d, syslog=%d, diagslog=%d]\n",
00505             level_name((DiagsLevel) i),
00506             config.outputs[i].to_stdout,
00507             config.outputs[i].to_stderr, config.outputs[i].to_syslog, config.outputs[i].to_diagslog);
00508   }
00509 }
00510 
00511 void
00512 Diags::log(const char *tag, DiagsLevel level,
00513            const char *file, const char *func, const int line,
00514            const char *format_string ...) const
00515 {
00516   if (! on(tag))
00517     return;
00518 
00519   va_list ap;
00520   va_start(ap, format_string);
00521   if (show_location) {
00522     SrcLoc lp(file, func, line);
00523     print_va(tag, level, &lp, format_string, ap);
00524   } else {
00525     print_va(tag, level, NULL, format_string, ap);
00526   }
00527   va_end(ap);
00528 }
00529 
00530 void
00531 Diags::error_va(DiagsLevel level,
00532              const char *file, const char *func, const int line,
00533              const char *format_string, va_list ap) const
00534 {
00535   va_list ap2;
00536 
00537   if (DiagsLevel_IsTerminal(level)) {
00538     va_copy(ap2, ap);
00539   }
00540 
00541   if (show_location) {
00542     SrcLoc lp(file, func, line);
00543     print_va(NULL, level, &lp, format_string, ap);
00544   } else {
00545     print_va(NULL, level, NULL, format_string, ap);
00546   }
00547 
00548   if (DiagsLevel_IsTerminal(level)) {
00549     if (cleanup_func)
00550       cleanup_func();
00551     ink_fatal_va(1, format_string, ap2);
00552   }
00553 }

Generated by  doxygen 1.7.1