mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 04:43:03 +01:00
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 Also, fix text alignment issue in detailed per-table perf stats
This commit is contained in:
parent
7d345af44d
commit
800baa6f44
@ -33,6 +33,7 @@
|
|||||||
#include "PluginLogWriter.h"
|
#include "PluginLogWriter.h"
|
||||||
#include "os/platform.h"
|
#include "os/platform.h"
|
||||||
#include "consts_pub.h"
|
#include "consts_pub.h"
|
||||||
|
#include "codetext.h"
|
||||||
#include "../../common/isc_f_proto.h"
|
#include "../../common/isc_f_proto.h"
|
||||||
#include "../../jrd/RuntimeStatistics.h"
|
#include "../../jrd/RuntimeStatistics.h"
|
||||||
#include "../../common/dsc.h"
|
#include "../../common/dsc.h"
|
||||||
@ -97,7 +98,9 @@ TracePluginImpl::TracePluginImpl(IPluginBase* plugin,
|
|||||||
transactions(getDefaultMemoryPool()),
|
transactions(getDefaultMemoryPool()),
|
||||||
statements(getDefaultMemoryPool()),
|
statements(getDefaultMemoryPool()),
|
||||||
services(getDefaultMemoryPool()),
|
services(getDefaultMemoryPool()),
|
||||||
unicodeCollation(*getDefaultMemoryPool())
|
unicodeCollation(*getDefaultMemoryPool()),
|
||||||
|
include_codes(*getDefaultMemoryPool()),
|
||||||
|
exclude_codes(*getDefaultMemoryPool())
|
||||||
{
|
{
|
||||||
const char* ses_name = initInfo->getTraceSessionName();
|
const char* ses_name = initInfo->getTraceSessionName();
|
||||||
session_name = ses_name && *ses_name ? ses_name : " ";
|
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;
|
operational = true;
|
||||||
log_init();
|
log_init();
|
||||||
}
|
}
|
||||||
@ -496,18 +506,30 @@ void TracePluginImpl::appendTableCounts(const PerformanceInfo *info)
|
|||||||
if (!config.print_perf || info->pin_count == 0)
|
if (!config.print_perf || info->pin_count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
record.append(NEWLINE
|
const TraceCounts* trc = info->pin_tables;
|
||||||
"Table Natural Index Update Insert Delete Backout Purge Expunge" NEWLINE
|
const TraceCounts* trc_end = trc + info->pin_count;
|
||||||
"***************************************************************************************************************" NEWLINE );
|
|
||||||
|
|
||||||
const TraceCounts* trc;
|
FB_SIZE_T max_len = 0;
|
||||||
const TraceCounts* trc_end;
|
for (; trc < trc_end; trc++)
|
||||||
|
{
|
||||||
|
FB_SIZE_T len = fb_strlen(trc->trc_relation_name);
|
||||||
|
if (max_len < len)
|
||||||
|
max_len = len;
|
||||||
|
};
|
||||||
|
if (max_len < 32)
|
||||||
|
max_len = 32;
|
||||||
|
|
||||||
|
record.append(NEWLINE"Table");
|
||||||
|
record.append(max_len - 5, ' ');
|
||||||
|
record.append(" Natural Index Update Insert Delete Backout Purge Expunge" NEWLINE);
|
||||||
|
record.append(max_len + 80, '*');
|
||||||
|
record.append(NEWLINE);
|
||||||
|
|
||||||
string temp;
|
string temp;
|
||||||
for (trc = info->pin_tables, trc_end = trc + info->pin_count; trc < trc_end; trc++)
|
for (trc = info->pin_tables; trc < trc_end; trc++)
|
||||||
{
|
{
|
||||||
record.append(trc->trc_relation_name);
|
record.append(trc->trc_relation_name);
|
||||||
record.append(MAX_SQL_IDENTIFIER_LEN - fb_strlen(trc->trc_relation_name), ' ');
|
record.append(max_len - fb_strlen(trc->trc_relation_name), ' ');
|
||||||
for (int j = 0; j < DBB_max_rel_count; j++)
|
for (int j = 0; j < DBB_max_rel_count; j++)
|
||||||
{
|
{
|
||||||
if (trc->trc_counters[j] == 0)
|
if (trc->trc_counters[j] == 0)
|
||||||
@ -548,6 +570,101 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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<Pair<NonPooled<const char*, ISC_STATUS> >, NocaseCmp > m_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
static InitInstance<GdsName2CodeMap> 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)
|
void TracePluginImpl::appendParams(ITraceParams* params)
|
||||||
{
|
{
|
||||||
const FB_SIZE_T paramcount = params->getCount();
|
const FB_SIZE_T paramcount = params->getCount();
|
||||||
@ -931,14 +1048,20 @@ void TracePluginImpl::appendServiceQueryParams(size_t send_item_length,
|
|||||||
|
|
||||||
void TracePluginImpl::log_init()
|
void TracePluginImpl::log_init()
|
||||||
{
|
{
|
||||||
record.printf("\tSESSION_%d %s" NEWLINE "\t%s" NEWLINE, session_id, session_name.c_str(), config.db_filename.c_str());
|
if (config.log_initfini)
|
||||||
logRecord("TRACE_INIT");
|
{
|
||||||
|
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()
|
void TracePluginImpl::log_finalize()
|
||||||
{
|
{
|
||||||
record.printf("\tSESSION_%d %s" NEWLINE "\t%s" NEWLINE, session_id, session_name.c_str(), config.db_filename.c_str());
|
if (config.log_initfini)
|
||||||
logRecord("TRACE_FINI");
|
{
|
||||||
|
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->release();
|
||||||
logWriter = NULL;
|
logWriter = NULL;
|
||||||
@ -2037,14 +2160,31 @@ void TracePluginImpl::log_event_trigger_execute(ITraceDatabaseConnection* connec
|
|||||||
void TracePluginImpl::log_event_error(ITraceConnection* connection, ITraceStatusVector* status,
|
void TracePluginImpl::log_event_error(ITraceConnection* connection, ITraceStatusVector* status,
|
||||||
const char* function)
|
const char* function)
|
||||||
{
|
{
|
||||||
if (!config.log_errors)
|
|
||||||
return;
|
|
||||||
|
|
||||||
string event_type;
|
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);
|
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);
|
event_type.printf("WARNING AT %s", function);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -172,12 +172,19 @@ private:
|
|||||||
Firebird::AutoPtr<Firebird::SimilarToMatcher<UCHAR, Jrd::UpcaseConverter<> > >
|
Firebird::AutoPtr<Firebird::SimilarToMatcher<UCHAR, Jrd::UpcaseConverter<> > >
|
||||||
include_matcher, exclude_matcher;
|
include_matcher, exclude_matcher;
|
||||||
|
|
||||||
|
// Filters for gds error codes
|
||||||
|
typedef Firebird::SortedArray<ISC_STATUS> GdsCodesArray;
|
||||||
|
GdsCodesArray include_codes;
|
||||||
|
GdsCodesArray exclude_codes;
|
||||||
|
|
||||||
void appendGlobalCounts(const PerformanceInfo* info);
|
void appendGlobalCounts(const PerformanceInfo* info);
|
||||||
void appendTableCounts(const PerformanceInfo* info);
|
void appendTableCounts(const PerformanceInfo* info);
|
||||||
void appendParams(Firebird::ITraceParams* params);
|
void appendParams(Firebird::ITraceParams* params);
|
||||||
void appendServiceQueryParams(size_t send_item_length, const ntrace_byte_t* send_items,
|
void appendServiceQueryParams(size_t send_item_length, const ntrace_byte_t* send_items,
|
||||||
size_t recv_item_length, const ntrace_byte_t* recv_items);
|
size_t recv_item_length, const ntrace_byte_t* recv_items);
|
||||||
void formatStringArgument(Firebird::string& result, const UCHAR* str, size_t len);
|
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
|
// register various objects
|
||||||
void register_connection(Firebird::ITraceDatabaseConnection* connection);
|
void register_connection(Firebird::ITraceDatabaseConnection* connection);
|
||||||
|
@ -95,6 +95,24 @@ database
|
|||||||
# Put errors happened
|
# Put errors happened
|
||||||
#log_errors = false
|
#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
|
# Sweep activity
|
||||||
#log_sweep = false
|
#log_sweep = false
|
||||||
|
|
||||||
@ -199,6 +217,24 @@ services
|
|||||||
|
|
||||||
# Put errors happened
|
# Put errors happened
|
||||||
#log_errors = false
|
#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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,6 +36,10 @@ STR_PARAMETER(include_filter, "")
|
|||||||
STR_PARAMETER(exclude_filter, "")
|
STR_PARAMETER(exclude_filter, "")
|
||||||
PATH_PARAMETER(log_filename, "")
|
PATH_PARAMETER(log_filename, "")
|
||||||
BOOL_PARAMETER(log_errors, false)
|
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)
|
BOOL_PARAMETER(enabled, false)
|
||||||
UINT_PARAMETER(max_log_size, 0)
|
UINT_PARAMETER(max_log_size, 0)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user