Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/build-gpdb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ jobs:
"contrib/xml2:installcheck"]
},
{"test":"ic-gpcontrib",
"make_configs":["gpcontrib/gp_array_agg:installcheck",
"make_configs":["gpcontrib/access_log:installcheck",
"gpcontrib/gp_array_agg:installcheck",
"gpcontrib/gp_debug_numsegments:installcheck",
"gpcontrib/gp_distribution_policy:installcheck",
"gpcontrib/gp_error_handling:installcheck",
Expand Down
7 changes: 5 additions & 2 deletions gpcontrib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ include $(top_builddir)/src/Makefile.global
recurse_targets = ""

ifeq "$(enable_debug_extensions)" "yes"
recurse_targets = gp_sparse_vector \
recurse_targets = access_log \
gp_sparse_vector \
gp_distribution_policy \
gp_parallel_retrieve_cursor \
gp_internal_tools \
Expand All @@ -30,7 +31,8 @@ ifeq "$(enable_debug_extensions)" "yes"
gp_interconnect_stats \
temp_tables_stat
else
recurse_targets = gp_sparse_vector \
recurse_targets = access_log \
gp_sparse_vector \
gp_distribution_policy \
gp_parallel_retrieve_cursor \
gp_internal_tools \
Expand Down Expand Up @@ -130,6 +132,7 @@ distclean:
if [ "${enable_orafce}" = "yes" ]; then $(MAKE) -C orafce NO_PGXS=true distclean; fi

installcheck:
$(MAKE) -C access_log installcheck
$(MAKE) -C gp_internal_tools installcheck
$(MAKE) -C gp_array_agg installcheck
$(MAKE) -C gp_aux_catalog installcheck
Expand Down
17 changes: 17 additions & 0 deletions gpcontrib/access_log/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# gpcontrib/access_log/Makefile

MODULE_big = access_log
OBJS = access_log.o

REGRESS = access_log

ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = gpcontrib/access_log
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
12 changes: 12 additions & 0 deletions gpcontrib/access_log/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# access_log

The extension logs when and which user initializes Seq Scan on which partition
or table. The log file name is pg_log/access.log. To activate the extension you
can use the shared_preload_libraries GUC or the LOAD command.

If you want to register Seq Scans on segments only you should load access_log
on segments and don't load on master:

```
gpconfig -c shared_preload_libraries -v 'access_log' -m ''
```
91 changes: 91 additions & 0 deletions gpcontrib/access_log/access_log.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include "postgres.h"

#include "catalog/pg_namespace.h"
#include "executor/nodeSeqscan.h"
#include "libpq/auth.h"
#include "utils/syscache.h"


PG_MODULE_MAGIC;

#define LOG_FILE_NAME "pg_log/access.log"

void _PG_init(void);


static init_scan_hook_type next_init_scan_hook = NULL;

static void
write_to_log(const char* str)
{
/*
* Synchronization is not necessary because `man write` says:
* "If the file was open(2)ed with O_APPEND, the file offset is first set to
* the end of the file before writing. The adjustment of the file offset and
* the write operation are performed as an atomic step."
*/
int f = open(LOG_FILE_NAME, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
if (f < 0 )
{
ereport(WARNING, (errcode_for_file_access(),
errmsg("could not open file " LOG_FILE_NAME)));
return;
}
write(f, str, strlen(str));
close(f);
}

static void
access_log_init_scan_hook(Relation currentRelation)
{
char buf[512];
HeapTuple tp;
struct timeval tv;

gettimeofday(&tv, NULL);
pg_strftime(buf, sizeof(buf),
"%Y-%m-%d %H:%M:%S %Z,",
pg_localtime((pg_time_t*)&tv.tv_sec, log_timezone));

/* paste milliseconds into place */
sprintf(buf + 19, ".%06d", (int) (tv.tv_usec));
/* restore space which has been rewritten by sprintf with \0 */
buf[19 + 1 + 6] = ' ';

if (MyProcPort != NULL && MyProcPort->user_name != NULL)
strlcat(buf, MyProcPort->user_name, sizeof(buf));
strlcat(buf, ",", sizeof(buf));

tp = SearchSysCache1(NAMESPACEOID,
ObjectIdGetDatum(currentRelation->rd_rel->relnamespace));
if (HeapTupleIsValid(tp))
{
Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
strlcat(buf, NameStr(nsptup->nspname), sizeof(buf));
strlcat(buf, ".", sizeof(buf));
ReleaseSysCache(tp);
}

strlcat(buf, NameStr(currentRelation->rd_rel->relname), sizeof(buf));
strlcat(buf, "\n", sizeof(buf));

write_to_log(buf);

if (next_init_scan_hook)
next_init_scan_hook(currentRelation);
}

void
_PG_init(void)
{
/* Be sure we do initialization only once */
static bool inited = false;

if (inited)
return;

next_init_scan_hook = init_scan_hook;
init_scan_hook = access_log_init_scan_hook;

inited = true;
}
Loading
Loading