File: logtofile_string_format.c

package info (click to toggle)
pgauditlogtofile 1.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 324 kB
  • sloc: ansic: 1,568; makefile: 26; sql: 12; sh: 7
file content (116 lines) | stat: -rw-r--r-- 3,188 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*-------------------------------------------------------------------------
 *
 * logtofile_string_format.c
 *      Functions to format data as strings
 *
 * Copyright (c) 2020-2026, Francisco Miguel Biete Banon
 *
 * This code is released under the PostgreSQL licence, as given at
 *  http://www.postgresql.org/about/licence/
 *-------------------------------------------------------------------------
 */
#include "logtofile_string_format.h"

#include "logtofile_autoclose.h"
#include "logtofile_guc.h"
#include "logtofile_shmem.h"
#include "logtofile_vars.h"

#include <access/xact.h>
#include <lib/stringinfo.h>
#include <libpq/libpq-be.h>
#include <miscadmin.h>
#include <pgtime.h>
#include <port/atomics.h>
#include <postmaster/syslogger.h>
#include <storage/fd.h>
#include <storage/ipc.h>
#include <storage/lwlock.h>
#include <storage/pg_shmem.h>
#include <storage/proc.h>
#include <tcop/tcopprot.h>
#include <utils/ps_status.h>
#include <utils/timestamp.h>
#include <stdint.h>

/**
 * @brief Formats the record time
 * @param t instr_time to format
 * @param buf buffer to write the formatted timestamp
 * @param len length of the buffer
 * @return void
 */
void PgAuditLogToFile_format_instr_time_nanos(instr_time t, char *buf, size_t len)
{
  instr_time now_instr;
  instr_time delta;
  TimestampTz now_ts;
  uint64_t delta_micro;
  TimestampTz t_ts;
  struct pg_tm tm;
  fsec_t fsec;
  const char *tzn;
  int tz;
  char tzbuf[16];
  uint64_t nsec;
  size_t cur_len;
  size_t remaining;

  /* capture current wall time and compute delta from provided instr_time */
  INSTR_TIME_SET_CURRENT(now_instr);
  delta = now_instr;
  INSTR_TIME_SUBTRACT(delta, t);

#if PG_VERSION_NUM >= 160000
  /* Use nanosecond resolution where available */
  {
    uint64_t delta_nano = INSTR_TIME_GET_NANOSEC(delta);
    delta_micro = delta_nano / 1000ULL;
  }
#else
  /* Fallback to microsecond resolution on older Postgres */
  delta_micro = INSTR_TIME_GET_MICROSEC(delta);
#endif

  now_ts = GetCurrentTimestamp();
  t_ts = now_ts - (TimestampTz) delta_micro;

  if (timestamp2tm(t_ts, &tz, &tm, &fsec, &tzn, log_timezone) == 0)
  {
    if (tzn == NULL)
    {
      int hours = tz / 3600;
      int mins = abs(tz % 3600) / 60;
      snprintf(tzbuf, sizeof(tzbuf), "%+03d:%02d", hours, mins);
      tzn = tzbuf;
    }
    if (tzn == NULL)
      tzn = "";

    /* Get nanoseconds from instr_time if available; fall back to microseconds*1000 */
  #if PG_VERSION_NUM >= 160000
    nsec = INSTR_TIME_GET_NANOSEC(t) % 1000000000ULL;
  #else
    nsec = (uint64_t) INSTR_TIME_GET_MICROSEC(t) * 1000ULL;
  #endif

    /* Print timestamp without timezone first */
    pg_snprintf(buf, len, "%04d-%02d-%02d %02d:%02d:%02d.%09llu",
          tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
          (unsigned long long) nsec);

    /* Safely append a space and the timezone, truncating if necessary */
    cur_len = strnlen(buf, len);
    if (cur_len < len - 1)
    {
      buf[cur_len] = ' ';
      buf[cur_len + 1] = '\0';
      remaining = len - cur_len - 1;
      strlcpy(buf + cur_len + 1, tzn, remaining);
    }
  }
  else
  {
    strlcpy(buf, "[invalid timestamp]", len);
  }
}