From 370572b2dd9a5d36156813b0042c69f437e66eb8 Mon Sep 17 00:00:00 2001 From: hvlad Date: Wed, 8 Feb 2017 13:38:02 +0200 Subject: [PATCH] Backport improvements CORE-5475 : Provide ability to filter out info and warnings from trace log, and CORE-4486 : Trace: provide filter to INCLUDE / EXCLUDE errors by their mnemonical names --- src/utilities/ntrace/TracePluginImpl.cpp | 152 +++++++++++++++++++++-- src/utilities/ntrace/TracePluginImpl.h | 7 ++ src/utilities/ntrace/fbtrace.conf | 36 ++++++ src/utilities/ntrace/paramtable.h | 4 + 4 files changed, 189 insertions(+), 10 deletions(-) diff --git a/src/utilities/ntrace/TracePluginImpl.cpp b/src/utilities/ntrace/TracePluginImpl.cpp index 5a551f39ce..257baa03e9 100644 --- a/src/utilities/ntrace/TracePluginImpl.cpp +++ b/src/utilities/ntrace/TracePluginImpl.cpp @@ -33,6 +33,7 @@ #include "PluginLogWriter.h" #include "os/platform.h" #include "consts_pub.h" +#include "codetext.h" #include "../../common/isc_f_proto.h" #include "../../jrd/RuntimeStatistics.h" #include "../../common/dsc.h" @@ -97,7 +98,9 @@ TracePluginImpl::TracePluginImpl(IPluginBase* plugin, transactions(getDefaultMemoryPool()), statements(getDefaultMemoryPool()), services(getDefaultMemoryPool()), - unicodeCollation(*getDefaultMemoryPool()) + unicodeCollation(*getDefaultMemoryPool()), + include_codes(*getDefaultMemoryPool()), + exclude_codes(*getDefaultMemoryPool()) { const char* ses_name = initInfo->getTraceSessionName(); session_name = ses_name && *ses_name ? ses_name : " "; @@ -163,6 +166,13 @@ TracePluginImpl::TracePluginImpl(IPluginBase* plugin, } } + // parse filters for gds error codes + if (!config.include_gds_codes.isEmpty()) + str2Array(config.include_gds_codes, include_codes); + + if (!config.exclude_gds_codes.isEmpty()) + str2Array(config.exclude_gds_codes, exclude_codes); + operational = true; log_init(); } @@ -548,6 +558,105 @@ void TracePluginImpl::formatStringArgument(string& result, const UCHAR* str, siz } +bool TracePluginImpl::filterStatus(const ISC_STATUS* status, GdsCodesArray& arr) +{ + FB_SIZE_T pos; + while (*status != isc_arg_end) + { + const ISC_STATUS s = *status; + switch (s) + { + case isc_arg_gds: + case isc_arg_warning: + if (arr.find(status[1], pos)) + return true; + status += 2; + break; + + case isc_arg_cstring: + status += 3; + break; + + default: + status += 2; + break; + } + } + + return false; +} + + +namespace { + +class GdsName2CodeMap +{ +public: + GdsName2CodeMap(MemoryPool& pool) : + m_map(pool) + { + for (int i = 0; codes[i].code_string; i++) + m_map.put(codes[i].code_string, codes[i].code_number); + } + + bool find(const char* name, ISC_STATUS& code) const + { + return m_map.get(name, code); + } + +private: + class NocaseCmp + { + public: + static bool greaterThan(const char* i1, const char* i2) + { + return fb_utils::stricmp(i1, i2) > 0; + } + }; + + GenericMap >, NocaseCmp > m_map; +}; + +}; // namespace + +static InitInstance gdsNamesMap; + +void TracePluginImpl::str2Array(const Firebird::string& str, GdsCodesArray& arr) +{ + // input: string with comma-delimited list of gds codes values and\or gds codes names + // output: sorted array of gds codes values + + const char *sep = " ,"; + + FB_SIZE_T p1 = 0, p2 = 0; + while (p2 < str.length()) + { + p2 = str.find_first_of(sep, p1); + if (p2 == string::npos) + p2 = str.length(); + + string s = str.substr(p1, p2 - p1); + + ISC_STATUS code = atol(s.c_str()); + + if (!code && !gdsNamesMap().find(s.c_str(), code)) + fatal_exception::raiseFmt( + "Error parsing error codes filter: \n" + "\t%s\n" + "\tbad item is: %s, at position: %d", + str.c_str(), s.c_str(), p1 + 1); + + // avoid duplicates + + FB_SIZE_T ins_pos; + if (!arr.find(code, ins_pos)) + arr.insert(ins_pos, code); + + p1 = str.find_first_not_of(sep, p2); + } +} + + void TracePluginImpl::appendParams(ITraceParams* params) { const FB_SIZE_T paramcount = params->getCount(); @@ -931,14 +1040,20 @@ void TracePluginImpl::appendServiceQueryParams(size_t send_item_length, void TracePluginImpl::log_init() { - record.printf("\tSESSION_%d %s" NEWLINE "\t%s" NEWLINE, session_id, session_name.c_str(), config.db_filename.c_str()); - logRecord("TRACE_INIT"); + if (config.log_initfini) + { + record.printf("\tSESSION_%d %s" NEWLINE "\t%s" NEWLINE, session_id, session_name.c_str(), config.db_filename.c_str()); + logRecord("TRACE_INIT"); + } } void TracePluginImpl::log_finalize() { - record.printf("\tSESSION_%d %s" NEWLINE "\t%s" NEWLINE, session_id, session_name.c_str(), config.db_filename.c_str()); - logRecord("TRACE_FINI"); + if (config.log_initfini) + { + record.printf("\tSESSION_%d %s" NEWLINE "\t%s" NEWLINE, session_id, session_name.c_str(), config.db_filename.c_str()); + logRecord("TRACE_FINI"); + } logWriter->release(); logWriter = NULL; @@ -2037,14 +2152,31 @@ void TracePluginImpl::log_event_trigger_execute(ITraceDatabaseConnection* connec void TracePluginImpl::log_event_error(ITraceConnection* connection, ITraceStatusVector* status, const char* function) { - if (!config.log_errors) - return; - string event_type; - if (status->hasError()) + if (config.log_errors && status->hasError()) + { + const ISC_STATUS* errs = status->getStatus()->getErrors(); + + if (!include_codes.isEmpty() && !filterStatus(errs, include_codes)) + return; + + if (!exclude_codes.isEmpty() && filterStatus(errs, exclude_codes)) + return; + event_type.printf("ERROR AT %s", function); - else if (status->hasWarning()) + } + else if (config.log_warnings && status->hasWarning()) + { + const ISC_STATUS* warns = status->getStatus()->getWarnings(); + + if (!include_codes.isEmpty() && !filterStatus(warns, include_codes)) + return; + + if (!exclude_codes.isEmpty() && filterStatus(warns, exclude_codes)) + return; + event_type.printf("WARNING AT %s", function); + } else return; diff --git a/src/utilities/ntrace/TracePluginImpl.h b/src/utilities/ntrace/TracePluginImpl.h index 1d1a8dec6b..2e1412d5f4 100644 --- a/src/utilities/ntrace/TracePluginImpl.h +++ b/src/utilities/ntrace/TracePluginImpl.h @@ -173,12 +173,19 @@ private: TraceSimilarToMatcher; Firebird::AutoPtr include_matcher, exclude_matcher; + // Filters for gds error codes + typedef Firebird::SortedArray GdsCodesArray; + GdsCodesArray include_codes; + GdsCodesArray exclude_codes; + void appendGlobalCounts(const PerformanceInfo* info); void appendTableCounts(const PerformanceInfo* info); void appendParams(Firebird::ITraceParams* params); void appendServiceQueryParams(size_t send_item_length, const ntrace_byte_t* send_items, size_t recv_item_length, const ntrace_byte_t* recv_items); void formatStringArgument(Firebird::string& result, const UCHAR* str, size_t len); + bool filterStatus(const ISC_STATUS* status, GdsCodesArray& arr); + void str2Array(const Firebird::string& str, GdsCodesArray& arr); // register various objects void register_connection(Firebird::ITraceDatabaseConnection* connection); diff --git a/src/utilities/ntrace/fbtrace.conf b/src/utilities/ntrace/fbtrace.conf index 8cc4e208e6..bff9a7fca7 100644 --- a/src/utilities/ntrace/fbtrace.conf +++ b/src/utilities/ntrace/fbtrace.conf @@ -95,6 +95,24 @@ database # Put errors happened #log_errors = false + # Put warnings + #log_warnings = false + + # Filters for errors and warnings GDS codes. + # Comma separated list of GDS codes values and\or names. + # For example: deadlock, req_sync, 335544321 + + # Include filter. If empty, trace all errors\warnings events. + # Else trace event if any code from list is found in status-vector. + #include_gds_codes + + # Exclude filter. If empty, trace all errors\warnings events. + # Else trace event if no code from list is found in status-vector. + #exclude_gds_codes + + # Put trace session init and finish messages + #log_initfini = true + # Sweep activity #log_sweep = false @@ -199,6 +217,24 @@ services # Put errors happened #log_errors = false + + # Put warnings + #log_warnings = false + + # Filters for errors and warnings GDS codes. + # Comma separated list of GDS codes values and\or names. + # For example: deadlock, req_sync, 335544321 + + # Include filter. If empty, trace all errors\warnings events. + # Else trace event if any code from list is found in status-vector. + #include_gds_codes + + # Exclude filter. If empty, trace all errors\warnings events. + # Else trace event if no code from list is found in status-vector. + #exclude_gds_codes + + # Put trace session init and finish messages + #log_initfini = true } diff --git a/src/utilities/ntrace/paramtable.h b/src/utilities/ntrace/paramtable.h index 0441666f9d..5c8a67e975 100644 --- a/src/utilities/ntrace/paramtable.h +++ b/src/utilities/ntrace/paramtable.h @@ -36,6 +36,10 @@ STR_PARAMETER(include_filter, "") STR_PARAMETER(exclude_filter, "") PATH_PARAMETER(log_filename, "") BOOL_PARAMETER(log_errors, false) +BOOL_PARAMETER(log_warnings, false) +STR_PARAMETER(include_gds_codes, "") +STR_PARAMETER(exclude_gds_codes, "") +BOOL_PARAMETER(log_initfini, true) BOOL_PARAMETER(enabled, false) UINT_PARAMETER(max_log_size, 0)