Skip to content

Commit

Permalink
pg_slow_log_stats() added
Browse files Browse the repository at this point in the history
  • Loading branch information
Anton Gorokhov committed Jun 18, 2020
1 parent 1a5e0b7 commit 66f51e4
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 7 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,17 @@ In output you can see 4 columns:
message: code of message from log_hook. (or 'TOTAL' for total count of that type messages)
count: count of massages of this type at this time_interval in log.

To get number of lines in slow log call `pg_slow_log_stats()`:

```
postgres=# select * from pg_slow_log_stats();
slow_count | reset_time
------------+----------------------------
1 | 2020-06-13 00:19:31.084923
(1 row)
```

To reset all statistics use
```
postgres=# select pg_log_errors_reset();
```
```
8 changes: 8 additions & 0 deletions logerrors--1.0--1.1.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE FUNCTION pg_slow_log_stats(
OUT slow_count integer,
OUT reset_time timestamp
)
RETURNS SETOF record
AS 'MODULE_PATHNAME', 'pg_slow_log_stats'
LANGUAGE C STRICT;
GRANT ALL ON FUNCTION pg_slow_log_stats() TO public;
87 changes: 81 additions & 6 deletions logerrors.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ void _PG_init(void);
void _PG_fini(void);

/* Shared memory init */
static void pgss_shmem_shutdown(int code, Datum arg);
static void pgss_shmem_startup(void);

/* Signal handling */
Expand Down Expand Up @@ -61,19 +60,27 @@ typedef struct message_info {
char *name;
} MessageInfo;

typedef struct slow_log_info {
pg_atomic_uint32 count;
pg_atomic_uint64 reset_time;
} SlowLogInfo;

/* Depends on message_types_count */
typedef struct global_info {
int interval;
int intervals_count;
/* index of current interval in buffer */
pg_atomic_uint32 current_interval_index;
pg_atomic_uint32 total_count[3];
SlowLogInfo slow_log_info;
} GlobalInfo;

static GlobalInfo *global_variables = NULL;

static HTAB *messages_info_hashtable = NULL;

void logerrors_emit_log_hook(ErrorData *edata);

static void
logerrors_sigterm(SIGNAL_ARGS)
{
Expand All @@ -93,6 +100,13 @@ global_variables_init()
global_variables->interval = interval;
}

static void
slow_log_info_init()
{
pg_atomic_init_u32(&global_variables->slow_log_info.count, 0);
pg_atomic_init_u64(&global_variables->slow_log_info.reset_time, GetCurrentTimestamp());
}

static void
logerrors_init()
{
Expand All @@ -104,7 +118,7 @@ logerrors_init()
elem = hash_search(messages_info_hashtable, (void *) &key, HASH_ENTER, &found);
for (int j = 0; j < message_types_count; ++j) {
pg_atomic_init_u32(&elem->message_count[j], 0);
elem->name = error_names[i];
elem->name = (char*)error_names[i];
MemSet(&(elem->intervals[j]), 0, max_number_of_intervals);
elem->sum_in_buffer[j] = 0;
}
Expand All @@ -114,6 +128,7 @@ logerrors_init()
for (int i = 0; i < message_types_count; ++i) {
pg_atomic_init_u32(&global_variables->total_count[i], 0);
}
slow_log_info_init();
}

static void
Expand Down Expand Up @@ -208,6 +223,10 @@ logerrors_emit_log_hook(ErrorData *edata)
pg_atomic_fetch_add_u32(&elem->message_count[j], 1);
pg_atomic_fetch_add_u32(&global_variables->total_count[j], 1);
}
if (edata && edata->message && strstr(edata->message, "duration:"))
{
pg_atomic_fetch_add_u32(&global_variables->slow_log_info.count, 1);
}
}

if (prev_emit_log_hook) {
Expand Down Expand Up @@ -249,6 +268,7 @@ logerrors_load_params(void)
void
_PG_init(void)
{
BackgroundWorker worker;
if (!process_shared_preload_libraries_in_progress) {
return;
}
Expand All @@ -257,7 +277,6 @@ _PG_init(void)
prev_emit_log_hook = emit_log_hook;
emit_log_hook = logerrors_emit_log_hook;
RequestAddinShmemSpace(sizeof(MessageInfo) * error_types_count + sizeof(GlobalInfo));
BackgroundWorker worker;
/* Worker parameter and registration */
MemSet(&worker, 0, sizeof(BackgroundWorker));
worker.bgw_flags = BGWORKER_SHMEM_ACCESS;
Expand All @@ -284,8 +303,6 @@ _PG_fini(void)
static void
pgss_shmem_startup(void) {
bool found;
ErrorCode key;
MessageInfo *elem;
HASHCTL ctl;
if (prev_shmem_startup_hook)
prev_shmem_startup_hook();
Expand Down Expand Up @@ -447,4 +464,62 @@ pg_log_errors_reset(PG_FUNCTION_ARGS) {
logerrors_init();

PG_RETURN_VOID();
}
}

PG_FUNCTION_INFO_V1(pg_slow_log_stats);

Datum
pg_slow_log_stats(PG_FUNCTION_ARGS)
{
#define SLOW_LOG_COLS 2
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
Tuplestorestate *tupstore;
TupleDesc tupdesc;
MemoryContext per_query_ctx;
MemoryContext oldcontext;

Datum result_values[SLOW_LOG_COLS];
bool result_nulls[SLOW_LOG_COLS];

/* Shmem structs not ready yet */
if (global_variables == NULL) {
return (Datum) 0;
}
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
if (!(rsinfo->allowedModes & SFRM_Materialize))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("materialize mode required, but it is not allowed in this context")));

/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("return type must be a row type")));

per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);

tupstore = tuplestore_begin_heap(true, false, work_mem);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
MemoryContextSwitchTo(oldcontext);

MemSet(result_values, 0, sizeof(result_values));
MemSet(result_nulls, 0, sizeof(result_nulls));
for (int i = 0; i < SLOW_LOG_COLS; i++) {
result_nulls[i] = false;
}
result_values[0] = DatumGetInt32(pg_atomic_read_u32(&global_variables->slow_log_info.count));
result_values[1] = DatumGetTimestamp(pg_atomic_read_u64(&global_variables->slow_log_info.reset_time));

tuplestore_putvalues(tupstore, tupdesc, result_values, result_nulls);
/* return the tuplestore */
tuplestore_donestoring(tupstore);
return (Datum) 0;
}

0 comments on commit 66f51e4

Please sign in to comment.