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

DiagsConfig.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 #include "libts.h"
00025 #include "I_Layout.h"
00026 #include "DiagsConfig.h"
00027 #include "P_RecCore.h"
00028 
00029 
00030 //////////////////////////////////////////////////////////////////////////////
00031 //
00032 //      void reconfigure_diags()
00033 //
00034 //      This function extracts the current diags configuration settings from
00035 //      records.config, and rebuilds the Diags data structures.
00036 //
00037 //////////////////////////////////////////////////////////////////////////////
00038 
00039 
00040 
00041 void
00042 DiagsConfig::reconfigure_diags()
00043 {
00044   int i, e;
00045   char *p, *dt, *at;
00046   DiagsConfigState c;
00047   bool found, all_found;
00048 
00049   static struct
00050   {
00051     const char *config_name;
00052     DiagsLevel level;
00053   } output_records[] = {
00054     {
00055     "proxy.config.diags.output.diag", DL_Diag}, {
00056     "proxy.config.diags.output.debug", DL_Debug}, {
00057     "proxy.config.diags.output.status", DL_Status}, {
00058     "proxy.config.diags.output.note", DL_Note}, {
00059     "proxy.config.diags.output.warning", DL_Warning}, {
00060     "proxy.config.diags.output.error", DL_Error}, {
00061     "proxy.config.diags.output.fatal", DL_Fatal}, {
00062     "proxy.config.diags.output.alert", DL_Alert}, {
00063     "proxy.config.diags.output.emergency", DL_Emergency}, {
00064     NULL, DL_Undefined}
00065   };
00066 
00067   if (!callbacks_established) {
00068     register_diags_callbacks();
00069   }
00070   ////////////////////////////////////////////
00071   // extract relevant records.config values //
00072   ////////////////////////////////////////////
00073 
00074   all_found = true;
00075 
00076   // initial value set to 0 or 1 based on command line tags
00077   c.enabled[DiagsTagType_Debug] = (diags->base_debug_tags != NULL);
00078   c.enabled[DiagsTagType_Action] = (diags->base_action_tags != NULL);
00079 
00080   // enabled if records.config set
00081 
00082   e = (int) REC_readInteger("proxy.config.diags.debug.enabled", &found);
00083   if (e && found)
00084     c.enabled[DiagsTagType_Debug] = 1;  // implement OR logic
00085   all_found = all_found && found;
00086 
00087   e = (int) REC_readInteger("proxy.config.diags.action.enabled", &found);
00088   if (e && found)
00089     c.enabled[DiagsTagType_Action] = 1; // implement OR logic
00090   all_found = all_found && found;
00091 
00092   e = (int) REC_readInteger("proxy.config.diags.show_location", &found);
00093   diags->show_location = ((e && found) ? 1 : 0);
00094   all_found = all_found && found;
00095 
00096   // read output routing values
00097   for (i = 0;; i++) {
00098     const char *record_name = output_records[i].config_name;
00099     DiagsLevel l = output_records[i].level;
00100 
00101     if (!record_name)
00102       break;
00103     p = REC_readString(record_name, &found);
00104     all_found = all_found && found;
00105     if (found) {
00106       parse_output_string(p, &(c.outputs[l]));
00107       ats_free(p);
00108     } else {
00109       diags->print(NULL, DTA(DL_Error), "can't find config variable '%s'\n", record_name);
00110     }
00111   }
00112 
00113   p = REC_readString("proxy.config.diags.debug.tags", &found);
00114   dt = (found ? p : NULL);      // NOTE: needs to be freed
00115   all_found = all_found && found;
00116 
00117   p = REC_readString("proxy.config.diags.action.tags", &found);
00118   at = (found ? p : NULL);      // NOTE: needs to be freed
00119   all_found = all_found && found;
00120 
00121   ///////////////////////////////////////////////////////////////////
00122   // if couldn't read all values, return without changing config,  //
00123   // otherwise rebuild taglists and change the diags config values //
00124   ///////////////////////////////////////////////////////////////////
00125 
00126   if (!all_found) {
00127     diags->print(NULL, DTA(DL_Error), "couldn't fetch all proxy.config.diags values");
00128   } else {
00129     //////////////////////////////
00130     // clear out old tag tables //
00131     //////////////////////////////
00132 
00133     diags->deactivate_all(DiagsTagType_Debug);
00134     diags->deactivate_all(DiagsTagType_Action);
00135 
00136     //////////////////////////////////////////////////////////////////////
00137     // add new tag tables from records.config or command line overrides //
00138     //////////////////////////////////////////////////////////////////////
00139 
00140     diags->activate_taglist((diags->base_debug_tags ? diags->base_debug_tags : dt), DiagsTagType_Debug);
00141     diags->activate_taglist((diags->base_action_tags ? diags->base_action_tags : at), DiagsTagType_Action);
00142 
00143     ////////////////////////////////////
00144     // change the diags config values //
00145     ////////////////////////////////////
00146 #if !defined(__GNUC__)
00147     diags->config = c;
00148 #else
00149     memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState));
00150 #endif
00151     diags->print(NULL, DTA(DL_Note), "updated diags config");
00152   }
00153 
00154   ////////////////////////////////////
00155   // free the record.config strings //
00156   ////////////////////////////////////
00157   ats_free(dt);
00158   ats_free(at);
00159 }
00160 
00161 
00162 //////////////////////////////////////////////////////////////////////////////
00163 //
00164 //      static void *diags_config_callback(void *opaque_token, void *data)
00165 //
00166 //      This is the records.config registration callback that is called
00167 //      when any diags value is changed.  Each time a diags value changes
00168 //      the entire diags state is reconfigured.
00169 //
00170 //////////////////////////////////////////////////////////////////////////////
00171 static int
00172 diags_config_callback(const char * /* name ATS_UNUSED */, RecDataT /* data_type ATS_UNUSED */,
00173                       RecData /* data ATS_UNUSED */, void *opaque_token)
00174 {
00175   DiagsConfig *diagsConfig;
00176 
00177   diagsConfig = (DiagsConfig *) opaque_token;
00178   ink_assert(diags->magic == DIAGS_MAGIC);
00179   diagsConfig->reconfigure_diags();
00180   return (0);
00181 }
00182 
00183 
00184 
00185 
00186 
00187 
00188 //////////////////////////////////////////////////////////////////////////////
00189 //
00190 //      void Diags::parse_output_string(char *s, DiagsModeOutput *o)
00191 //
00192 //      This routine converts a diags outpur routing string <s> to the
00193 //      internal DiagsModeOutput structure.  Currently there are 4 possible
00194 //      routing destinations:
00195 //              O  stdout
00196 //              E  stderr
00197 //              S  syslog
00198 //              L  diags.log
00199 //
00200 //////////////////////////////////////////////////////////////////////////////
00201 
00202 void
00203 DiagsConfig::parse_output_string(char *s, DiagsModeOutput * o)
00204 {
00205   o->to_stdout = (s && strchr(s, 'O'));
00206   o->to_stderr = (s && strchr(s, 'E'));
00207   o->to_syslog = (s && strchr(s, 'S'));
00208   o->to_diagslog = (s && strchr(s, 'L'));
00209 }
00210 
00211 
00212 //////////////////////////////////////////////////////////////////////////////
00213 //
00214 //      void Diags::config_norecords()
00215 //
00216 //      Builds the Diags data structures based on the command line values
00217 //        it does not use any of the records based config variables
00218 //
00219 //////////////////////////////////////////////////////////////////////////////
00220 void
00221 DiagsConfig::config_diags_norecords()
00222 {
00223   DiagsConfigState c;
00224 
00225   //////////////////////////////
00226   // clear out old tag tables //
00227   //////////////////////////////
00228   diags->deactivate_all(DiagsTagType_Debug);
00229   diags->deactivate_all(DiagsTagType_Action);
00230 
00231   //////////////////////////////////////////////////////////////////////
00232   // add new tag tables from command line overrides only              //
00233   //////////////////////////////////////////////////////////////////////
00234 
00235   if (diags->base_debug_tags) {
00236     diags->activate_taglist(diags->base_debug_tags, DiagsTagType_Debug);
00237     c.enabled[DiagsTagType_Debug] = 1;
00238   } else {
00239     c.enabled[DiagsTagType_Debug] = 0;
00240   }
00241 
00242   if (diags->base_action_tags) {
00243     diags->activate_taglist(diags->base_action_tags, DiagsTagType_Action);
00244     c.enabled[DiagsTagType_Action] = 1;
00245   } else {
00246     c.enabled[DiagsTagType_Action] = 0;
00247   }
00248 
00249 #if !defined(__GNUC__)
00250   diags->config = c;
00251 #else
00252   memcpy(((void *) &diags->config), ((void *) &c), sizeof(DiagsConfigState));
00253 #endif
00254 }
00255 
00256 void
00257 DiagsConfig::RegisterDiagConfig()
00258 {
00259   RecRegisterConfigInt(RECT_CONFIG, "proxy.config.diags.debug.enabled", 0, RECU_NULL, RECC_NULL, NULL);
00260   RecRegisterConfigString(RECT_CONFIG, "proxy.config.diags.debug.tags", "", RECU_NULL, RECC_NULL, NULL);
00261   RecRegisterConfigInt(RECT_CONFIG, "proxy.config.diags.action.enabled", 0, RECU_NULL, RECC_NULL, NULL);
00262   RecRegisterConfigString(RECT_CONFIG, "proxy.config.diags.action.tags", "", RECU_NULL, RECC_NULL, NULL);
00263   RecRegisterConfigInt(RECT_CONFIG, "proxy.config.diags.show_location", 0, RECU_NULL, RECC_NULL, NULL);
00264   RecRegisterConfigString(RECT_CONFIG, "proxy.config.diags.output.diag", "L", RECU_NULL, RECC_NULL, NULL);
00265   RecRegisterConfigString(RECT_CONFIG, "proxy.config.diags.output.debug", "L", RECU_NULL, RECC_NULL, NULL);
00266   RecRegisterConfigString(RECT_CONFIG, "proxy.config.diags.output.status", "L", RECU_NULL, RECC_NULL, NULL);
00267   RecRegisterConfigString(RECT_CONFIG, "proxy.config.diags.output.note", "L", RECU_NULL, RECC_NULL, NULL);
00268   RecRegisterConfigString(RECT_CONFIG, "proxy.config.diags.output.warning", "L", RECU_NULL, RECC_NULL, NULL);
00269   RecRegisterConfigString(RECT_CONFIG, "proxy.config.diags.output.error", "SL", RECU_NULL, RECC_NULL, NULL);
00270   RecRegisterConfigString(RECT_CONFIG, "proxy.config.diags.output.fatal", "SL", RECU_NULL, RECC_NULL, NULL);
00271   RecRegisterConfigString(RECT_CONFIG, "proxy.config.diags.output.alert", "L", RECU_NULL, RECC_NULL, NULL);
00272   RecRegisterConfigString(RECT_CONFIG, "proxy.config.diags.output.emergency", "SL", RECU_NULL, RECC_NULL, NULL);
00273 }
00274 
00275 
00276 DiagsConfig::DiagsConfig(const char * filename, const char * tags, const char * actions, bool use_records)
00277 {
00278   char diags_logpath[PATH_NAME_MAX + 1];
00279   ats_scoped_str logpath;
00280 
00281   callbacks_established = false;
00282   diags_log_fp = (FILE *) NULL;
00283   diags = NULL;
00284 
00285   ////////////////////////////////////////////////////////////////////
00286   //  If we aren't using the manager records for configuation       //
00287   //   just build the tables based on command line parameters and   //
00288   //   exit                                                         //
00289   ////////////////////////////////////////////////////////////////////
00290 
00291   if (!use_records) {
00292     diags = new Diags(tags, actions, NULL);
00293     config_diags_norecords();
00294     return;
00295   }
00296 
00297   // Open the diagnostics log. If proxy.config.log.logfile_dir is set use that, otherwise fall
00298   // back to the configured log directory.
00299 
00300   logpath = RecConfigReadLogDir();
00301   if (access(logpath, W_OK | R_OK) == -1) {
00302     fprintf(stderr, "unable to access log directory '%s': %d, %s\n",
00303             (const char *)logpath, errno, strerror(errno));
00304     fprintf(stderr, "please set 'proxy.config.log.logfile_dir'\n");
00305     _exit(1);
00306   }
00307 
00308   ink_filepath_make(diags_logpath, sizeof(diags_logpath), logpath, filename);
00309 
00310   // open write append
00311   // diags_log_fp = fopen(diags_logpath,"w");
00312   diags_log_fp = fopen(diags_logpath, "a+");
00313   if (diags_log_fp) {
00314     int status;
00315     status = setvbuf(diags_log_fp, NULL, _IOLBF, 512);
00316     if (status != 0) {
00317       fclose(diags_log_fp);
00318       diags_log_fp = NULL;
00319     }
00320   }
00321 
00322   diags = new Diags(tags, actions, diags_log_fp);
00323   if (diags_log_fp == NULL) {
00324 
00325     diags->print(NULL, DTA(DL_Warning),
00326                  "couldn't open diags log file '%s', " "will not log to this file", diags_logpath);
00327   }
00328   diags->print(NULL, DTA(DL_Status), "opened %s", diags_logpath);
00329 
00330   register_diags_callbacks();
00331 
00332   reconfigure_diags();
00333 
00334 }
00335 
00336 
00337 //////////////////////////////////////////////////////////////////////////////
00338 //
00339 //      void DiagsConfig::register_diags_callbacks()
00340 //
00341 //      set up management callbacks to update diags on every change ---   //
00342 //      right now, this system kind of sucks, we rebuild the tag tables //
00343 //      from scratch for *every* proxy.config.diags value that changed; //
00344 //      dgourley is looking into changing the management API to provide //
00345 //      a callback each time records.config changed, possibly better.   //
00346 //
00347 //////////////////////////////////////////////////////////////////////////////
00348 void
00349 DiagsConfig::register_diags_callbacks()
00350 {
00351 
00352   static const char *config_record_names[] = {
00353     "proxy.config.diags.debug.enabled",
00354     "proxy.config.diags.debug.tags",
00355     "proxy.config.diags.action.enabled",
00356     "proxy.config.diags.action.tags",
00357     "proxy.config.diags.show_location",
00358     "proxy.config.diags.output.diag",
00359     "proxy.config.diags.output.debug",
00360     "proxy.config.diags.output.status",
00361     "proxy.config.diags.output.note",
00362     "proxy.config.diags.output.warning",
00363     "proxy.config.diags.output.error",
00364     "proxy.config.diags.output.fatal",
00365     "proxy.config.diags.output.alert",
00366     "proxy.config.diags.output.emergency",
00367     NULL
00368   };
00369 
00370   bool total_status = true;
00371   bool status;
00372   int i;
00373   void *o = (void *) this;
00374 
00375   // set triggers to call same callback for any diag config change
00376   for (i = 0; config_record_names[i] != NULL; i++) {
00377     status = (REC_RegisterConfigUpdateFunc(config_record_names[i], diags_config_callback, o) == REC_ERR_OKAY);
00378     if (!status) {
00379       diags->print(NULL, DTA(DL_Warning),
00380                    "couldn't register variable '%s', is records.config up to date?", config_record_names[i]);
00381     }
00382     total_status = total_status && status;
00383   }
00384 
00385   if (total_status == false) {
00386     diags->print(NULL, DTA(DL_Error), "couldn't setup all diags callbacks, diagnostics may misbehave");
00387     callbacks_established = false;
00388   } else {
00389     callbacks_established = true;
00390   }
00391 
00392 }
00393 
00394 DiagsConfig::~DiagsConfig()
00395 {
00396   if (diags_log_fp) {
00397     fclose(diags_log_fp);
00398     diags_log_fp = NULL;
00399   }
00400   delete diags;
00401 }

Generated by  doxygen 1.7.1