LCOV - code coverage report
Current view: top level - src/common - logging.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 72 105 68.6 %
Date: 2019-06-19 14:06:47 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  * Logging framework for frontend programs
       3             :  *
       4             :  * Copyright (c) 2018-2019, PostgreSQL Global Development Group
       5             :  *
       6             :  * src/common/logging.c
       7             :  *
       8             :  *-------------------------------------------------------------------------
       9             :  */
      10             : #include "postgres_fe.h"
      11             : 
      12             : #include <unistd.h>
      13             : 
      14             : #include "common/logging.h"
      15             : 
      16             : enum pg_log_level __pg_log_level;
      17             : 
      18             : static const char *progname;
      19             : static int  log_flags;
      20             : 
      21             : static void (*log_pre_callback) (void);
      22             : static void (*log_locus_callback) (const char **, uint64 *);
      23             : 
      24             : static const char *sgr_error = NULL;
      25             : static const char *sgr_warning = NULL;
      26             : static const char *sgr_locus = NULL;
      27             : 
      28             : #define SGR_ERROR_DEFAULT "01;31"
      29             : #define SGR_WARNING_DEFAULT "01;35"
      30             : #define SGR_LOCUS_DEFAULT "01"
      31             : 
      32             : #define ANSI_ESCAPE_FMT "\x1b[%sm"
      33             : #define ANSI_ESCAPE_RESET "\x1b[0m"
      34             : 
      35             : /*
      36             :  * This should be called before any output happens.
      37             :  */
      38             : void
      39        6868 : pg_logging_init(const char *argv0)
      40             : {
      41        6868 :     const char *pg_color_env = getenv("PG_COLOR");
      42        6868 :     bool        log_color = false;
      43             : 
      44             :     /* usually the default, but not on Windows */
      45        6868 :     setvbuf(stderr, NULL, _IONBF, 0);
      46             : 
      47        6868 :     progname = get_progname(argv0);
      48        6868 :     __pg_log_level = PG_LOG_INFO;
      49             : 
      50        6868 :     if (pg_color_env)
      51             :     {
      52           0 :         if (strcmp(pg_color_env, "always") == 0 ||
      53           0 :             (strcmp(pg_color_env, "auto") == 0 && isatty(fileno(stderr))))
      54           0 :             log_color = true;
      55             :     }
      56             : 
      57        6868 :     if (log_color)
      58             :     {
      59           0 :         const char *pg_colors_env = getenv("PG_COLORS");
      60             : 
      61           0 :         if (pg_colors_env)
      62             :         {
      63           0 :             char       *colors = strdup(pg_colors_env);
      64             : 
      65           0 :             if (colors)
      66             :             {
      67           0 :                 for (char *token = strtok(colors, ":"); token; token = strtok(NULL, ":"))
      68             :                 {
      69           0 :                     char       *e = strchr(token, '=');
      70             : 
      71           0 :                     if (e)
      72             :                     {
      73             :                         char       *name;
      74             :                         char       *value;
      75             : 
      76           0 :                         *e = '\0';
      77           0 :                         name = token;
      78           0 :                         value = e + 1;
      79             : 
      80           0 :                         if (strcmp(name, "error") == 0)
      81           0 :                             sgr_error = strdup(value);
      82           0 :                         if (strcmp(name, "warning") == 0)
      83           0 :                             sgr_warning = strdup(value);
      84           0 :                         if (strcmp(name, "locus") == 0)
      85           0 :                             sgr_locus = strdup(value);
      86             :                     }
      87             :                 }
      88             : 
      89           0 :                 free(colors);
      90             :             }
      91             :         }
      92             :         else
      93             :         {
      94           0 :             sgr_error = SGR_ERROR_DEFAULT;
      95           0 :             sgr_warning = SGR_WARNING_DEFAULT;
      96           0 :             sgr_locus = SGR_LOCUS_DEFAULT;
      97             :         }
      98             :     }
      99        6868 : }
     100             : 
     101             : void
     102        6334 : pg_logging_config(int new_flags)
     103             : {
     104        6334 :     log_flags = new_flags;
     105        6334 : }
     106             : 
     107             : void
     108         404 : pg_logging_set_level(enum pg_log_level new_level)
     109             : {
     110         404 :     __pg_log_level = new_level;
     111         404 : }
     112             : 
     113             : void
     114        3970 : pg_logging_set_pre_callback(void (*cb) (void))
     115             : {
     116        3970 :     log_pre_callback = cb;
     117        3970 : }
     118             : 
     119             : void
     120        3970 : pg_logging_set_locus_callback(void (*cb) (const char **filename, uint64 *lineno))
     121             : {
     122        3970 :     log_locus_callback = cb;
     123        3970 : }
     124             : 
     125             : void
     126       45312 : pg_log_generic(enum pg_log_level level, const char *pg_restrict fmt,...)
     127             : {
     128             :     va_list     ap;
     129             : 
     130       45312 :     va_start(ap, fmt);
     131       45312 :     pg_log_generic_v(level, fmt, ap);
     132       45312 :     va_end(ap);
     133       45312 : }
     134             : 
     135             : void
     136       45312 : pg_log_generic_v(enum pg_log_level level, const char *pg_restrict fmt, va_list ap)
     137             : {
     138       45312 :     int         save_errno = errno;
     139       45312 :     const char *filename = NULL;
     140       45312 :     uint64      lineno = 0;
     141             :     va_list     ap2;
     142             :     size_t      required_len;
     143             :     char       *buf;
     144             : 
     145             :     Assert(progname);
     146             :     Assert(level);
     147             :     Assert(fmt);
     148             :     Assert(fmt[strlen(fmt) - 1] != '\n');
     149             : 
     150             :     /*
     151             :      * Flush stdout before output to stderr, to ensure sync even when stdout
     152             :      * is buffered.
     153             :      */
     154       45312 :     fflush(stdout);
     155             : 
     156       45312 :     if (log_pre_callback)
     157       28134 :         log_pre_callback();
     158             : 
     159       45312 :     if (log_locus_callback)
     160       28134 :         log_locus_callback(&filename, &lineno);
     161             : 
     162       45312 :     fmt = _(fmt);
     163             : 
     164       45312 :     if (!(log_flags & PG_LOG_FLAG_TERSE) || filename)
     165             :     {
     166       17638 :         if (sgr_locus)
     167           0 :             fprintf(stderr, ANSI_ESCAPE_FMT, sgr_locus);
     168       17638 :         if (!(log_flags & PG_LOG_FLAG_TERSE))
     169       17638 :             fprintf(stderr, "%s:", progname);
     170       17638 :         if (filename)
     171             :         {
     172         132 :             fprintf(stderr, "%s:", filename);
     173         132 :             if (lineno > 0)
     174         132 :                 fprintf(stderr, UINT64_FORMAT ":", lineno);
     175             :         }
     176       17638 :         fprintf(stderr, " ");
     177       17638 :         if (sgr_locus)
     178           0 :             fprintf(stderr, ANSI_ESCAPE_RESET);
     179             :     }
     180             : 
     181       45312 :     if (!(log_flags & PG_LOG_FLAG_TERSE))
     182             :     {
     183       17638 :         switch (level)
     184             :         {
     185             :             case PG_LOG_FATAL:
     186           8 :                 if (sgr_error)
     187           0 :                     fprintf(stderr, ANSI_ESCAPE_FMT, sgr_error);
     188           8 :                 fprintf(stderr, _("fatal: "));
     189           8 :                 if (sgr_error)
     190           0 :                     fprintf(stderr, ANSI_ESCAPE_RESET);
     191           8 :                 break;
     192             :             case PG_LOG_ERROR:
     193         530 :                 if (sgr_error)
     194           0 :                     fprintf(stderr, ANSI_ESCAPE_FMT, sgr_error);
     195         530 :                 fprintf(stderr, _("error: "));
     196         530 :                 if (sgr_error)
     197           0 :                     fprintf(stderr, ANSI_ESCAPE_RESET);
     198         530 :                 break;
     199             :             case PG_LOG_WARNING:
     200         140 :                 if (sgr_warning)
     201           0 :                     fprintf(stderr, ANSI_ESCAPE_FMT, sgr_warning);
     202         140 :                 fprintf(stderr, _("warning: "));
     203         140 :                 if (sgr_warning)
     204           0 :                     fprintf(stderr, ANSI_ESCAPE_RESET);
     205         140 :                 break;
     206             :             default:
     207       16960 :                 break;
     208             :         }
     209             :     }
     210             : 
     211       45312 :     errno = save_errno;
     212             : 
     213       45312 :     va_copy(ap2, ap);
     214       45312 :     required_len = vsnprintf(NULL, 0, fmt, ap2) + 1;
     215       45312 :     va_end(ap2);
     216             : 
     217       45312 :     buf = pg_malloc_extended(required_len, MCXT_ALLOC_NO_OOM);
     218             : 
     219       45312 :     if (!buf)
     220             :     {
     221             :         /* memory trouble, just print what we can and get out of here */
     222           0 :         vfprintf(stderr, fmt, ap);
     223           0 :         return;
     224             :     }
     225             : 
     226       45312 :     vsnprintf(buf, required_len, fmt, ap);
     227             : 
     228             :     /* strip one newline, for PQerrorMessage() */
     229       45312 :     if (required_len >= 2 && buf[required_len - 2] == '\n')
     230       28022 :         buf[required_len - 2] = '\0';
     231             : 
     232       45312 :     fprintf(stderr, "%s\n", buf);
     233             : 
     234       45312 :     free(buf);
     235             : }

Generated by: LCOV version 1.13