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 15:15:32 Functions: 100.0 % 8 8 8
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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
      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;
      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 */
     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                 :     {
     107 UBC           0 :         if (strcmp(pg_color_env, "always") == 0 ||
     108               0 :             (strcmp(pg_color_env, "auto") == 0 && color_terminal))
     109               0 :             log_color = true;
     110                 :     }
     111                 : 
     112 CBC        9526 :     if (log_color)
     113                 :     {
     114 UBC           0 :         const char *pg_colors_env = getenv("PG_COLORS");
     115                 : 
     116               0 :         if (pg_colors_env)
     117                 :         {
     118               0 :             char       *colors = strdup(pg_colors_env);
     119                 : 
     120               0 :             if (colors)
     121                 :             {
     122               0 :                 for (char *token = strtok(colors, ":"); token; token = strtok(NULL, ":"))
     123                 :                 {
     124               0 :                     char       *e = strchr(token, '=');
     125                 : 
     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);
     139               0 :                         if (strcmp(name, "note") == 0)
     140               0 :                             sgr_note = strdup(value);
     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;
     153               0 :             sgr_note = SGR_NOTE_DEFAULT;
     154               0 :             sgr_locus = SGR_LOCUS_DEFAULT;
     155                 :         }
     156                 :     }
     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
     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
     193            6482 : pg_logging_set_pre_callback(void (*cb) (void))
     194                 : {
     195            6482 :     log_pre_callback = cb;
     196            6482 : }
     197                 : 
     198                 : void
     199            6482 : pg_logging_set_locus_callback(void (*cb) (const char **filename, uint64 *lineno))
     200                 : {
     201            6482 :     log_locus_callback = cb;
     202            6482 : }
     203                 : 
     204                 : void
     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                 : 
     210           71897 :     va_start(ap, fmt);
     211           71897 :     pg_log_generic_v(level, part, fmt, ap);
     212           71897 :     va_end(ap);
     213           71897 : }
     214                 : 
     215                 : void
     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                 : {
     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. */
     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                 :      */
     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                 : 
     249           44711 :     if (!(log_flags & PG_LOG_FLAG_TERSE) || filename)
     250                 :     {
     251           17937 :         if (sgr_locus)
     252 UBC           0 :             fprintf(stderr, ANSI_ESCAPE_FMT, sgr_locus);
     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)
     263 UBC           0 :             fprintf(stderr, ANSI_ESCAPE_RESET);
     264                 :     }
     265                 : 
     266 CBC       44711 :     if (!(log_flags & PG_LOG_FLAG_TERSE))
     267                 :     {
     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)
     275 UBC           0 :                             fprintf(stderr, ANSI_ESCAPE_FMT, sgr_error);
     276 CBC         830 :                         fprintf(stderr, _("error: "));
     277             830 :                         if (sgr_error)
     278 UBC           0 :                             fprintf(stderr, ANSI_ESCAPE_RESET);
     279 CBC         830 :                         break;
     280             132 :                     case PG_LOG_WARNING:
     281             132 :                         if (sgr_warning)
     282 UBC           0 :                             fprintf(stderr, ANSI_ESCAPE_FMT, sgr_warning);
     283 CBC         132 :                         fprintf(stderr, _("warning: "));
     284             132 :                         if (sgr_warning)
     285 UBC           0 :                             fprintf(stderr, ANSI_ESCAPE_RESET);
     286 CBC         132 :                         break;
     287           16804 :                     default:
     288           16804 :                         break;
     289                 :                 }
     290           17766 :                 break;
     291               9 :             case PG_LOG_DETAIL:
     292               9 :                 if (sgr_note)
     293 UBC           0 :                     fprintf(stderr, ANSI_ESCAPE_FMT, sgr_note);
     294 CBC           9 :                 fprintf(stderr, _("detail: "));
     295               9 :                 if (sgr_note)
     296 UBC           0 :                     fprintf(stderr, ANSI_ESCAPE_RESET);
     297 CBC           9 :                 break;
     298             162 :             case PG_LOG_HINT:
     299             162 :                 if (sgr_note)
     300 UBC           0 :                     fprintf(stderr, ANSI_ESCAPE_FMT, sgr_note);
     301 CBC         162 :                 fprintf(stderr, _("hint: "));
     302             162 :                 if (sgr_note)
     303 UBC           0 :                     fprintf(stderr, ANSI_ESCAPE_RESET);
     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                 : 
     316           44711 :     errno = save_errno;         /* malloc might change errno */
     317                 : 
     318           44711 :     if (!buf)
     319                 :     {
     320                 :         /* memory trouble, just print what we can and get out of here */
     321 UBC           0 :         vfprintf(stderr, fmt, ap);
     322               0 :         return;
     323                 :     }
     324                 : 
     325 CBC       44711 :     vsnprintf(buf, required_len, fmt, ap);
     326                 : 
     327                 :     /* strip one newline, for PQerrorMessage() */
     328           44711 :     if (required_len >= 2 && buf[required_len - 2] == '\n')
     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