<commit_before>/** @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.
 */

/****************************************************************************

  Diags.cc

  This file contains code to manipulate run-time diagnostics, and print
  warnings and errors at runtime.  Action tags and debugging tags are
  supported, allowing run-time conditionals affecting diagnostics.

  Joe User should only need to use the macros at the bottom of Diags.h


 ****************************************************************************/

#include "ink_platform.h"
#include "ink_memory.h"
#include "ink_defs.h"
#include "ink_error.h"
#include "ink_assert.h"
#include "ink_time.h"
#include "ink_hrtime.h"
#include "Diags.h"
#include "Compatability.h"


int diags_on_for_plugins = 0;
bool DiagsConfigState::enabled[2] = { false, false };

// Global, used for all diagnostics
inkcoreapi Diags *diags = NULL;

//////////////////////////////////////////////////////////////////////////////
//
//      char *SrcLoc::str(char *buf, int buflen)
//
//      This method takes a SrcLoc source location data structure and
//      converts it to a human-readable representation, in the buffer <buf>
//      with length <buflen>.  The buffer will always be NUL-terminated, and
//      must always have a length of at least 1.  The buffer address is
//      returned on success.  The routine will only fail if the SrcLoc is
//      not valid, or the buflen is less than 1.
//
//////////////////////////////////////////////////////////////////////////////

char *
SrcLoc::str(char *buf, int buflen) const
{
  const char * shortname;

  if (!this->valid() || buflen < 1)
    return (NULL);

  shortname = strrchr(file, '/');
  shortname = shortname ? (shortname + 1) : file;

  if (func != NULL) {
    snprintf(buf, buflen, "%s:%d (%s)", shortname, line, func);
  } else {
    snprintf(buf, buflen, "%s:%d", shortname, line);
  }
  buf[buflen - 1] = NUL;
  return (buf);
}




//////////////////////////////////////////////////////////////////////////////
//
//      Diags::Diags(char *bdt, char *bat)
//
//      This is the constructor for the Diags class.  The constructor takes
//      two strings called the "base debug tags" (bdt) and the
//      "base action tags" (bat).  These represent debug/action overrides,
//      to override the records.config values.  They current come from
//      command-line options.
//
//      If bdt is not NULL, and not "", it overrides records.config settings.
//      If bat is not NULL, and not "", it overrides records.config settings.
//
//      When the constructor is done, records.config callbacks will be set,
//      the initial values read, and the Diags instance will be ready to use.
//
//////////////////////////////////////////////////////////////////////////////

Diags::Diags(const char *bdt, const char *bat, FILE * _diags_log_fp)
  : diags_log_fp(_diags_log_fp), magic(DIAGS_MAGIC), show_location(0),
    base_debug_tags(NULL), base_action_tags(NULL)
{
  int i;

  cleanup_func = NULL;
  ink_mutex_init(&tag_table_lock, "Diags::tag_table_lock");

  ////////////////////////////////////////////////////////
  // initialize the default, base debugging/action tags //
  ////////////////////////////////////////////////////////

  if (bdt && *bdt) {
    base_debug_tags = ats_strdup(bdt);
  }
  if (bat && *bat) {
    base_action_tags = ats_strdup(bat);
  }

  config.enabled[DiagsTagType_Debug] = (base_debug_tags != NULL);
  config.enabled[DiagsTagType_Action] = (base_action_tags != NULL);
  diags_on_for_plugins = config.enabled[DiagsTagType_Debug];

  for (i = 0; i < DiagsLevel_Count; i++) {
    config.outputs[i].to_stdout = false;
    config.outputs[i].to_stderr = false;
    config.outputs[i].to_syslog = false;
    config.outputs[i].to_diagslog = true;
  }

  //////////////////////////////////////////////////////////////////
  // start off with empty tag tables, will build in reconfigure() //
  //////////////////////////////////////////////////////////////////

  activated_tags[DiagsTagType_Debug] = NULL;
  activated_tags[DiagsTagType_Action] = NULL;
  prefix_str = "";

}

Diags::~Diags()
{
  diags_log_fp = NULL;

  ats_free((void *)base_debug_tags);
  ats_free((void *)base_action_tags);

  deactivate_all(DiagsTagType_Debug);
  deactivate_all(DiagsTagType_Action);
}


//////////////////////////////////////////////////////////////////////////////
//
//      void Diags::print_va(...)
//
//      This is the lowest-level diagnostic printing routine, that does the
//      work of formatting and outputting diagnostic and error messages,
//      in the standard format.
//
//      This routine takes an optional <debug_tag>, which is printed in
//      parentheses if its value is not NULL.  It takes a <diags_level>,
//      which is converted to a prefix string.
//      print_va takes an optional source location structure pointer <loc>,
//      which can be NULL.  If <loc> is not NULL, the source code location
//      is converted to a string, and printed between angle brackets.
//      Finally, it takes a printf format string <format_string>, and a
//      va_list list of varargs.
//
//      This routine outputs to all of the output targets enabled for this
//      debugging level in config.outputs[diags_level].  Many higher level
//      diagnosting printing routines are built upon print_va, including:
//
//              void print(...)
//              void log_va(...)
//              void log(...)
//
//////////////////////////////////////////////////////////////////////////////

void
Diags::print_va(const char *debug_tag, DiagsLevel diags_level, const SrcLoc *loc,
                const char *format_string, va_list ap) const
{
  struct timeval tp;
  const char *s;
  char *buffer, *d, timestamp_buf[48];
  char format_buf[1024], format_buf_w_ts[1024], *end_of_format;

  ////////////////////////////////////////////////////////////////////////
  // there are 2 format buffers that hold a printf-style format string  //
  // format_buf contains <prefix_string>: (<debug_tag>) <format_string> //
  // and format_buf_w_ts has the same thing with a prepended timestamp. //
  ////////////////////////////////////////////////////////////////////////

  format_buf[0] = NUL;
  format_buf_w_ts[0] = NUL;

  /////////////////////////////////////////////////////<commit_msg>TS-3287: abort on bogus diagnostic levels<commit_after>/** @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.
 */

/****************************************************************************

  Diags.cc

  This file contains code to manipulate run-time diagnostics, and print
  warnings and errors at runtime.  Action tags and debugging tags are
  supported, allowing run-time conditionals affecting diagnostics.

  Joe User should only need to use the macros at the bottom of Diags.h


 ****************************************************************************/

#include "ink_platform.h"
#include "ink_memory.h"
#include "ink_defs.h"
#include "ink_error.h"
#include "ink_assert.h"
#include "ink_time.h"
#include "ink_hrtime.h"
#include "Diags.h"
#include "Compatability.h"


int diags_on_for_plugins = 0;
bool DiagsConfigState::enabled[2] = { false, false };

// Global, used for all diagnostics
inkcoreapi Diags *diags = NULL;

//////////////////////////////////////////////////////////////////////////////
//
//      char *SrcLoc::str(char *buf, int buflen)
//
//      This method takes a SrcLoc source location data structure and
//      converts it to a human-readable representation, in the buffer <buf>
//      with length <buflen>.  The buffer will always be NUL-terminated, and
//      must always have a length of at least 1.  The buffer address is
//      returned on success.  The routine will only fail if the SrcLoc is
//      not valid, or the buflen is less than 1.
//
//////////////////////////////////////////////////////////////////////////////

char *
SrcLoc::str(char *buf, int buflen) const
{
  const char * shortname;

  if (!this->valid() || buflen < 1)
    return (NULL);

  shortname = strrchr(file, '/');
  shortname = shortname ? (shortname + 1) : file;

  if (func != NULL) {
    snprintf(buf, buflen, "%s:%d (%s)", shortname, line, func);
  } else {
    snprintf(buf, buflen, "%s:%d", shortname, line);
  }
  buf[buflen - 1] = NUL;
  return (buf);
}




//////////////////////////////////////////////////////////////////////////////
//
//      Diags::Diags(char *bdt, char *bat)
//
//      This is the constructor for the Diags class.  The constructor takes
//      two strings called the "base debug tags" (bdt) and the
//      "base action tags" (bat).  These represent debug/action overrides,
//      to override the records.config values.  They current come from
//      command-line options.
//
//      If bdt is not NULL, and not "", it overrides records.config settings.
//      If bat is not NULL, and not "", it overrides records.config settings.
//
//      When the constructor is done, records.config callbacks will be set,
//      the initial values read, and the Diags instance will be ready to use.
//
//////////////////////////////////////////////////////////////////////////////

Diags::Diags(const char *bdt, const char *bat, FILE * _diags_log_fp)
  : diags_log_fp(_diags_log_fp), magic(DIAGS_MAGIC), show_location(0),
    base_debug_tags(NULL), base_action_tags(NULL)
{
  int i;

  cleanup_func = NULL;
  ink_mutex_init(&tag_table_lock, "Diags::tag_table_lock");

  ////////////////////////////////////////////////////////
  // initialize the default, base debugging/action tags //
  ////////////////////////////////////////////////////////

  if (bdt && *bdt) {
    base_debug_tags = ats_strdup(bdt);
  }
  if (bat && *bat) {
    base_action_tags = ats_strdup(bat);
  }

  config.enabled[DiagsTagType_Debug] = (base_debug_tags != NULL);
  config.enabled[DiagsTagType_Action] = (base_action_tags != NULL);
  diags_on_for_plugins = config.enabled[DiagsTagType_Debug];

  for (i = 0; i < DiagsLevel_Count; i++) {
    config.outputs[i].to_stdout = false;
    config.outputs[i].to_stderr = false;
    config.outputs[i].to_syslog = false;
    config.outputs[i].to_diagslog = true;
  }

  //////////////////////////////////////////////////////////////////
  // start off with empty tag tables, will build in reconfigure() //
  //////////////////////////////////////////////////////////////////

  activated_tags[DiagsTagType_Debug] = NULL;
  activated_tags[DiagsTagType_Action] = NULL;
  prefix_str = "";

}

Diags::~Diags()
{
  diags_log_fp = NULL;

  ats_free((void *)base_debug_tags);
  ats_free((void *)base_action_tags);

  deactivate_all(DiagsTagType_Debug);
  deactivate_all(DiagsTagType_Action);
}


//////////////////////////////////////////////////////////////////////////////
//
//      void Diags::print_va(...)
//
//      This is the lowest-level diagnostic printing routine, that does the
//      work of formatting and outputting diagnostic and error messages,
//      in the standard format.
//
//      This routine takes an optional <debug_tag>, which is printed in
//      parentheses if its value is not NULL.  It takes a <diags_level>,
//      which is converted to a prefix string.
//      print_va takes an optional source location structure pointer <loc>,
//      which can be NULL.  If <loc> is not NULL, the source code location
//      is converted to a string, and printed between angle brackets.
//      Finally, it takes a printf format string <format_string>, and a
//      va_list list of varargs.
//
//      This routine outputs to all of the output targets enabled for this
//      debugging level in config.outputs[diags_level].  Many higher level
//      diagnosting printing routines are built upon print_va, including:
//
//              void print(...)
//              void log_va(...)
//              void log(...)
//
//////////////////////////////////////////////////////////////////////////////

void
Diags::print_va(const char *debug_tag, DiagsLevel diags_level, const SrcLoc *loc,
                const char *format_string, va_list ap) const
{
  struct timeval tp;
  const char *s;
  char *buffer, *d, timestamp_buf[48];
  char format_buf[1024], format_buf_w_ts[1024], *end_of_format;

  ink_release_assert(diags_level < DiagsLevel_Count);

  ////////////////////////////////////////////////////////////////////////
  // there are 2 format buffers that hold a printf-style format string  //
  // format_buf contains <prefix_string>: (<debug_tag>) <format_string> //
  // and format_buf_w_ts has the same thing with a prepended timestamp. //
  ////////////////////////////////////////////////////////////////////////

  format_buf[0] = NUL;
  format_buf_w_ts[0] = NUL;

  /////////////////////////////////////////////////////
{'fraction_non_alphanumeric': 0.2357865364492501, 'fraction_numerical': 0.003906522497384025, 'mean_word_length': 2.0048207922867323, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7437772', 'n_tokens_mistral': 3945, 'n_tokens_neox': 3815, 'n_words': 1347}