8
0
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:
hvlad 2017-02-05 11:40:49 +02:00
parent 7d345af44d
commit 800baa6f44
4 changed files with 204 additions and 17 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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
} }

View File

@ -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)