LCOV - differential code coverage report
Current view: top level - src/common - logging.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 71.4 % 133 95 38 95
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 8 8 8
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 71.4 % 133 95 38 95
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 100.0 % 8 8 8

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  * Logging framework for frontend programs
                                  3                 :  *
                                  4                 :  * Copyright (c) 2018-2023, PostgreSQL Global Development Group
                                  5                 :  *
                                  6                 :  * src/common/logging.c
                                  7                 :  *
                                  8                 :  *-------------------------------------------------------------------------
                                  9                 :  */
                                 10                 : 
                                 11                 : #ifndef FRONTEND
                                 12                 : #error "This file is not expected to be compiled for backend code"
                                 13                 : #endif
                                 14                 : 
                                 15                 : #include "postgres_fe.h"
                                 16                 : 
                                 17                 : #include <unistd.h>
                                 18                 : 
                                 19                 : #include "common/logging.h"
                                 20                 : 
                                 21                 : enum pg_log_level __pg_log_level;
                                 22                 : 
                                 23                 : static const char *progname;
                                 24                 : static int  log_flags;
                                 25                 : 
                                 26                 : static void (*log_pre_callback) (void);
                                 27                 : static void (*log_locus_callback) (const char **, uint64 *);
                                 28                 : 
                                 29                 : static const char *sgr_error = NULL;
                                 30                 : static const char *sgr_warning = NULL;
                                 31                 : static const char *sgr_note = NULL;
                                 32                 : static const char *sgr_locus = NULL;
                                 33                 : 
                                 34                 : #define SGR_ERROR_DEFAULT "01;31"
                                 35                 : #define SGR_WARNING_DEFAULT "01;35"
                                 36                 : #define SGR_NOTE_DEFAULT "01;36"
                                 37                 : #define SGR_LOCUS_DEFAULT "01"
                                 38                 : 
                                 39                 : #define ANSI_ESCAPE_FMT "\x1b[%sm"
                                 40                 : #define ANSI_ESCAPE_RESET "\x1b[0m"
                                 41                 : 
                                 42                 : #ifdef WIN32
                                 43                 : 
                                 44                 : #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
                                 45                 : #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
                                 46                 : #endif
                                 47                 : 
                                 48                 : /*
                                 49                 :  * Attempt to enable VT100 sequence processing for colorization on Windows.
                                 50                 :  * If current environment is not VT100-compatible or if this mode could not
                                 51                 :  * be enabled, return false.
                                 52                 :  */
                                 53                 : static bool
                                 54                 : enable_vt_processing(void)
                                 55                 : {
                                 56                 :     /* Check stderr */
                                 57                 :     HANDLE      hOut = GetStdHandle(STD_ERROR_HANDLE);
                                 58                 :     DWORD       dwMode = 0;
                                 59                 : 
                                 60                 :     if (hOut == INVALID_HANDLE_VALUE)
                                 61                 :         return false;
                                 62                 : 
                                 63                 :     /*
                                 64                 :      * Look for the current console settings and check if VT100 is already
                                 65                 :      * enabled.
                                 66                 :      */
                                 67                 :     if (!GetConsoleMode(hOut, &dwMode))
                                 68                 :         return false;
                                 69                 :     if ((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0)
                                 70                 :         return true;
                                 71                 : 
                                 72                 :     dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
                                 73                 :     if (!SetConsoleMode(hOut, dwMode))
                                 74                 :         return false;
                                 75                 :     return true;
                                 76                 : }
                                 77                 : #endif                          /* WIN32 */
                                 78                 : 
                                 79                 : /*
                                 80                 :  * This should be called before any output happens.
                                 81                 :  */
                                 82                 : void
 1469 peter                      83 CBC        9526 : pg_logging_init(const char *argv0)
                                 84                 : {
                                 85            9526 :     const char *pg_color_env = getenv("PG_COLOR");
                                 86            9526 :     bool        log_color = false;
 1133 michael                    87            9526 :     bool        color_terminal = isatty(fileno(stderr));
                                 88                 : 
                                 89                 : #ifdef WIN32
                                 90                 : 
                                 91                 :     /*
                                 92                 :      * On Windows, check if environment is VT100-compatible if using a
                                 93                 :      * terminal.
                                 94                 :      */
                                 95                 :     if (color_terminal)
                                 96                 :         color_terminal = enable_vt_processing();
                                 97                 : #endif
                                 98                 : 
                                 99                 :     /* usually the default, but not on Windows */
 1469 peter                     100            9526 :     setvbuf(stderr, NULL, _IONBF, 0);
                                101                 : 
                                102            9526 :     progname = get_progname(argv0);
                                103            9526 :     __pg_log_level = PG_LOG_INFO;
                                104                 : 
                                105            9526 :     if (pg_color_env)
                                106                 :     {
 1469 peter                     107 UBC           0 :         if (strcmp(pg_color_env, "always") == 0 ||
 1133 michael                   108               0 :             (strcmp(pg_color_env, "auto") == 0 && color_terminal))
 1469 peter                     109               0 :             log_color = true;
                                110                 :     }
                                111                 : 
 1469 peter                     112 CBC        9526 :     if (log_color)
                                113                 :     {
 1469 peter                     114 UBC           0 :         const char *pg_colors_env = getenv("PG_COLORS");
                                115                 : 
                                116               0 :         if (pg_colors_env)
                                117                 :         {
 1418 tgl                       118               0 :             char       *colors = strdup(pg_colors_env);
                                119                 : 
 1469 peter                     120               0 :             if (colors)
                                121                 :             {
                                122               0 :                 for (char *token = strtok(colors, ":"); token; token = strtok(NULL, ":"))
                                123                 :                 {
 1418 tgl                       124               0 :                     char       *e = strchr(token, '=');
                                125                 : 
 1469 peter                     126               0 :                     if (e)
                                127                 :                     {
                                128                 :                         char       *name;
                                129                 :                         char       *value;
                                130                 : 
                                131               0 :                         *e = '\0';
                                132               0 :                         name = token;
                                133               0 :                         value = e + 1;
                                134                 : 
                                135               0 :                         if (strcmp(name, "error") == 0)
                                136               0 :                             sgr_error = strdup(value);
                                137               0 :                         if (strcmp(name, "warning") == 0)
                                138               0 :                             sgr_warning = strdup(value);
  363                           139               0 :                         if (strcmp(name, "note") == 0)
                                140               0 :                             sgr_note = strdup(value);
 1469                           141               0 :                         if (strcmp(name, "locus") == 0)
                                142               0 :                             sgr_locus = strdup(value);
                                143                 :                     }
                                144                 :                 }
                                145                 : 
                                146               0 :                 free(colors);
                                147                 :             }
                                148                 :         }
                                149                 :         else
                                150                 :         {
                                151               0 :             sgr_error = SGR_ERROR_DEFAULT;
                                152               0 :             sgr_warning = SGR_WARNING_DEFAULT;
  363                           153               0 :             sgr_note = SGR_NOTE_DEFAULT;
 1469                           154               0 :             sgr_locus = SGR_LOCUS_DEFAULT;
                                155                 :         }
                                156                 :     }
 1469 peter                     157 CBC        9526 : }
                                158                 : 
                                159                 : /*
                                160                 :  * Change the logging flags.
                                161                 :  */
                                162                 : void
                                163           12258 : pg_logging_config(int new_flags)
                                164                 : {
                                165           12258 :     log_flags = new_flags;
                                166           12258 : }
                                167                 : 
                                168                 : /*
                                169                 :  * pg_logging_init sets the default log level to INFO.  Programs that prefer
                                170                 :  * a different default should use this to set it, immediately afterward.
                                171                 :  */
                                172                 : void
                                173             258 : pg_logging_set_level(enum pg_log_level new_level)
                                174                 : {
                                175             258 :     __pg_log_level = new_level;
                                176             258 : }
                                177                 : 
                                178                 : /*
                                179                 :  * Command line switches such as --verbose should invoke this.
                                180                 :  */
                                181                 : void
  934 tgl                       182              43 : pg_logging_increase_verbosity(void)
                                183                 : {
                                184                 :     /*
                                185                 :      * The enum values are chosen such that we have to decrease __pg_log_level
                                186                 :      * in order to become more verbose.
                                187                 :      */
                                188              43 :     if (__pg_log_level > PG_LOG_NOTSET + 1)
                                189              43 :         __pg_log_level--;
                                190              43 : }
                                191                 : 
                                192                 : void
 1418                           193            6482 : pg_logging_set_pre_callback(void (*cb) (void))
                                194                 : {
 1469 peter                     195            6482 :     log_pre_callback = cb;
                                196            6482 : }
                                197                 : 
                                198                 : void
 1418 tgl                       199            6482 : pg_logging_set_locus_callback(void (*cb) (const char **filename, uint64 *lineno))
                                200                 : {
 1469 peter                     201            6482 :     log_locus_callback = cb;
                                202            6482 : }
                                203                 : 
                                204                 : void
  366 tgl                       205           71897 : pg_log_generic(enum pg_log_level level, enum pg_log_part part,
                                206                 :                const char *pg_restrict fmt,...)
                                207                 : {
                                208                 :     va_list     ap;
                                209                 : 
 1469 peter                     210           71897 :     va_start(ap, fmt);
  366 tgl                       211           71897 :     pg_log_generic_v(level, part, fmt, ap);
 1469 peter                     212           71897 :     va_end(ap);
                                213           71897 : }
                                214                 : 
                                215                 : void
  366 tgl                       216           71949 : pg_log_generic_v(enum pg_log_level level, enum pg_log_part part,
                                217                 :                  const char *pg_restrict fmt, va_list ap)
                                218                 : {
 1469 peter                     219           71949 :     int         save_errno = errno;
                                220           71949 :     const char *filename = NULL;
                                221           71949 :     uint64      lineno = 0;
                                222                 :     va_list     ap2;
                                223                 :     size_t      required_len;
                                224                 :     char       *buf;
                                225                 : 
                                226           71949 :     Assert(progname);
                                227           71949 :     Assert(level);
                                228           71949 :     Assert(fmt);
                                229           71949 :     Assert(fmt[strlen(fmt) - 1] != '\n');
                                230                 : 
                                231                 :     /* Do nothing if log level is too low. */
  362 tgl                       232           71949 :     if (level < __pg_log_level)
                                233           27238 :         return;
                                234                 : 
                                235                 :     /*
                                236                 :      * Flush stdout before output to stderr, to ensure sync even when stdout
                                237                 :      * is buffered.
                                238                 :      */
 1469 peter                     239           44711 :     fflush(stdout);
                                240                 : 
                                241           44711 :     if (log_pre_callback)
                                242           27375 :         log_pre_callback();
                                243                 : 
                                244           44711 :     if (log_locus_callback)
                                245           27375 :         log_locus_callback(&filename, &lineno);
                                246                 : 
                                247           44711 :     fmt = _(fmt);
                                248                 : 
  314                           249           44711 :     if (!(log_flags & PG_LOG_FLAG_TERSE) || filename)
                                250                 :     {
 1469                           251           17937 :         if (sgr_locus)
 1469 peter                     252 UBC           0 :             fprintf(stderr, ANSI_ESCAPE_FMT, sgr_locus);
 1469 peter                     253 CBC       17937 :         if (!(log_flags & PG_LOG_FLAG_TERSE))
                                254           17937 :             fprintf(stderr, "%s:", progname);
                                255           17937 :         if (filename)
                                256                 :         {
                                257             306 :             fprintf(stderr, "%s:", filename);
                                258             306 :             if (lineno > 0)
                                259             306 :                 fprintf(stderr, UINT64_FORMAT ":", lineno);
                                260                 :         }
                                261           17937 :         fprintf(stderr, " ");
                                262           17937 :         if (sgr_locus)
 1469 peter                     263 UBC           0 :             fprintf(stderr, ANSI_ESCAPE_RESET);
                                264                 :     }
                                265                 : 
 1469 peter                     266 CBC       44711 :     if (!(log_flags & PG_LOG_FLAG_TERSE))
                                267                 :     {
  366 tgl                       268           17937 :         switch (part)
                                269                 :         {
                                270           17766 :             case PG_LOG_PRIMARY:
                                271                 :                 switch (level)
                                272                 :                 {
                                273             830 :                     case PG_LOG_ERROR:
                                274             830 :                         if (sgr_error)
  366 tgl                       275 UBC           0 :                             fprintf(stderr, ANSI_ESCAPE_FMT, sgr_error);
  366 tgl                       276 CBC         830 :                         fprintf(stderr, _("error: "));
                                277             830 :                         if (sgr_error)
  366 tgl                       278 UBC           0 :                             fprintf(stderr, ANSI_ESCAPE_RESET);
  366 tgl                       279 CBC         830 :                         break;
                                280             132 :                     case PG_LOG_WARNING:
                                281             132 :                         if (sgr_warning)
  366 tgl                       282 UBC           0 :                             fprintf(stderr, ANSI_ESCAPE_FMT, sgr_warning);
  366 tgl                       283 CBC         132 :                         fprintf(stderr, _("warning: "));
                                284             132 :                         if (sgr_warning)
  366 tgl                       285 UBC           0 :                             fprintf(stderr, ANSI_ESCAPE_RESET);
  366 tgl                       286 CBC         132 :                         break;
                                287           16804 :                     default:
                                288           16804 :                         break;
                                289                 :                 }
 1469 peter                     290           17766 :                 break;
  366 tgl                       291               9 :             case PG_LOG_DETAIL:
  363 peter                     292               9 :                 if (sgr_note)
  363 peter                     293 UBC           0 :                     fprintf(stderr, ANSI_ESCAPE_FMT, sgr_note);
  366 tgl                       294 CBC           9 :                 fprintf(stderr, _("detail: "));
  363 peter                     295               9 :                 if (sgr_note)
  363 peter                     296 UBC           0 :                     fprintf(stderr, ANSI_ESCAPE_RESET);
 1469 peter                     297 CBC           9 :                 break;
  366 tgl                       298             162 :             case PG_LOG_HINT:
  363 peter                     299             162 :                 if (sgr_note)
  363 peter                     300 UBC           0 :                     fprintf(stderr, ANSI_ESCAPE_FMT, sgr_note);
  366 tgl                       301 CBC         162 :                 fprintf(stderr, _("hint: "));
  363 peter                     302             162 :                 if (sgr_note)
  363 peter                     303 UBC           0 :                     fprintf(stderr, ANSI_ESCAPE_RESET);
 1469 peter                     304 CBC         162 :                 break;
                                305                 :         }
                                306                 :     }
                                307                 : 
                                308           44711 :     errno = save_errno;
                                309                 : 
                                310           44711 :     va_copy(ap2, ap);
                                311           44711 :     required_len = vsnprintf(NULL, 0, fmt, ap2) + 1;
                                312           44711 :     va_end(ap2);
                                313                 : 
                                314           44711 :     buf = pg_malloc_extended(required_len, MCXT_ALLOC_NO_OOM);
                                315                 : 
 1373 tgl                       316           44711 :     errno = save_errno;         /* malloc might change errno */
                                317                 : 
 1469 peter                     318           44711 :     if (!buf)
                                319                 :     {
                                320                 :         /* memory trouble, just print what we can and get out of here */
 1469 peter                     321 UBC           0 :         vfprintf(stderr, fmt, ap);
                                322               0 :         return;
                                323                 :     }
                                324                 : 
 1469 peter                     325 CBC       44711 :     vsnprintf(buf, required_len, fmt, ap);
                                326                 : 
                                327                 :     /* strip one newline, for PQerrorMessage() */
 1426 tgl                       328           44711 :     if (required_len >= 2 && buf[required_len - 2] == '\n')
 1469 peter                     329           26872 :         buf[required_len - 2] = '\0';
                                330                 : 
                                331           44711 :     fprintf(stderr, "%s\n", buf);
                                332                 : 
                                333           44711 :     free(buf);
                                334                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a