Coverage Report

Created: 2023-05-28 06:42

/src/netcdf-c/libdispatch/nclog.c
Line
Count
Source (jump to first uncovered line)
1
/*********************************************************************
2
 *   Copyright 2018, UCAR/Unidata
3
 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4
 *   $Header$
5
 *********************************************************************/
6
7
#include "config.h"
8
#ifdef _MSC_VER
9
#include<io.h>
10
#endif
11
12
#include <stdlib.h>
13
#include <stdio.h>
14
#include <stdarg.h>
15
#include <string.h>
16
#include <errno.h>
17
#ifdef HAVE_FCNTL_H
18
#include <fcntl.h>
19
#endif
20
#ifdef HAVE_UNISTD_H
21
#include <unistd.h>
22
#endif
23
 
24
#ifdef HAVE_EXECINFO_H
25
#include <execinfo.h>
26
#endif
27
28
#include "netcdf.h"
29
#include "nclog.h"
30
31
#define PREFIXLEN 8
32
#define MAXTAGS 256
33
#define NCTAGDFALT "Log";
34
35
#define NC_MAX_FRAMES 1024
36
37
static int nclogginginitialized = 0;
38
39
static struct NCLOGGLOBAL {
40
    int nclogging;
41
    int tracelevel;
42
    FILE* nclogstream;
43
    int depth;
44
    struct Frame {
45
  const char* fcn;
46
  int level;
47
  int depth;
48
    } frames[NC_MAX_FRAMES];
49
} nclog_global = {0,-1,NULL};
50
51
static const char* nctagset[] = {"Note","Warning","Error","Debug"};
52
static const int nctagsize = sizeof(nctagset)/sizeof(char*);
53
54
/* Forward */
55
static const char* nctagname(int tag);
56
 
57
/*!\defgroup NClog NClog Management
58
@{*/
59
60
/*!\internal
61
*/
62
63
void
64
ncloginit(void)
65
1
{
66
1
    const char* envv = NULL;
67
1
    if(nclogginginitialized)
68
0
  return;
69
1
    nclogginginitialized = 1;
70
1
    memset(&nclog_global,0,sizeof(nclog_global));
71
1
    nclog_global.tracelevel = -1;    
72
1
    ncsetlogging(0);
73
1
    nclog_global.nclogstream = stderr;
74
    /* Use environment variables to preset nclogging state*/
75
    /* I hope this is portable*/
76
1
    envv = getenv(NCENVLOGGING);
77
1
    if(envv != NULL) {
78
0
  ncsetlogging(1);
79
0
    }
80
1
    envv = getenv(NCENVTRACING);
81
1
    if(envv != NULL) {
82
0
  nctracelevel(atoi(envv));
83
0
    }
84
1
}
85
86
/*!
87
Enable/Disable logging.
88
89
\param[in] tf If 1, then turn on logging, if 0, then turn off logging.
90
91
\return The previous value of the logging flag.
92
*/
93
94
int
95
ncsetlogging(int tf)
96
1
{
97
1
    int was;
98
1
    if(!nclogginginitialized) ncloginit();
99
1
    was = nclog_global.nclogging;
100
1
    nclog_global.nclogging = tf;
101
1
    if(nclog_global.nclogstream == NULL) nclogopen(NULL);
102
1
    return was;
103
1
}
104
105
int
106
nclogopen(FILE* stream)
107
1
{
108
1
    if(!nclogginginitialized) ncloginit();
109
1
    if(stream == NULL) stream = stderr;
110
1
    nclog_global.nclogstream = stream;
111
1
    return 1;
112
1
}
113
114
/*!
115
Send logging messages. This uses a variable
116
number of arguments and operates like the stdio
117
printf function.
118
119
\param[in] tag Indicate the kind of this log message.
120
\param[in] format Format specification as with printf.
121
*/
122
123
void
124
nclog(int tag, const char* fmt, ...)
125
3
{
126
3
    if(fmt != NULL) {
127
3
      va_list args;
128
3
      va_start(args, fmt);
129
3
      ncvlog(tag,fmt,args);
130
3
      va_end(args);
131
3
    }
132
3
}
133
134
int
135
ncvlog(int tag, const char* fmt, va_list ap)
136
3
{
137
3
    const char* prefix;
138
3
    int was = -1;
139
140
3
    if(!nclogginginitialized) ncloginit();
141
3
    if(tag == NCLOGERR) was = ncsetlogging(1);
142
3
    if(!nclog_global.nclogging || nclog_global.nclogstream == NULL) return was;
143
0
    prefix = nctagname(tag);
144
0
    fprintf(nclog_global.nclogstream,"%s: ",prefix);
145
0
    if(fmt != NULL) {
146
0
      vfprintf(nclog_global.nclogstream, fmt, ap);
147
0
    }
148
0
    fprintf(nclog_global.nclogstream, "\n" );
149
0
    fflush(nclog_global.nclogstream);
150
0
    return was;
151
3
}
152
153
void
154
nclogtext(int tag, const char* text)
155
0
{
156
0
    nclogtextn(tag,text,strlen(text));
157
0
}
158
159
/*!
160
Send arbitrarily long text as a logging message.
161
Each line will be sent using nclog with the specified tag.
162
\param[in] tag Indicate the kind of this log message.
163
\param[in] text Arbitrary text to send as a logging message.
164
*/
165
166
void
167
nclogtextn(int tag, const char* text, size_t count)
168
0
{
169
0
    NC_UNUSED(tag);
170
0
    if(!nclog_global.nclogging || nclog_global.nclogstream == NULL) return;
171
0
    fwrite(text,1,count,nclog_global.nclogstream);
172
0
    fflush(nclog_global.nclogstream);
173
0
}
174
175
static const char*
176
nctagname(int tag)
177
0
{
178
0
    if(tag < 0 || tag >= nctagsize)
179
0
  return "unknown";
180
0
    return nctagset[tag];
181
0
}
182
183
/*!
184
Send trace messages.
185
\param[in] level Indicate the level of trace
186
\param[in] format Format specification as with printf.
187
*/
188
189
int
190
nctracelevel(int level)
191
0
{
192
0
    int oldlevel;
193
0
    if(!nclogginginitialized) ncloginit();
194
0
    oldlevel = nclog_global.tracelevel;
195
0
    if(level < 0) {
196
0
      nclog_global.tracelevel = level;
197
0
      ncsetlogging(0);
198
0
    } else { /*(level >= 0)*/
199
0
        nclog_global.tracelevel = level;
200
0
        ncsetlogging(1);
201
0
  nclogopen(NULL); /* use stderr */    
202
0
    }
203
0
    return oldlevel;
204
0
}
205
206
void
207
nctrace(int level, const char* fcn, const char* fmt, ...)
208
0
{
209
0
    va_list args;
210
0
    va_start(args, fmt);
211
0
    ncvtrace(level,fcn,fmt,args);
212
0
    va_end(args);
213
0
}
214
215
void
216
nctracemore(int level, const char* fmt, ...)
217
0
{
218
0
    va_list args;
219
0
    va_start(args, fmt);
220
0
    ncvtrace(level,NULL,fmt,args);
221
0
    va_end(args);
222
0
}
223
224
void
225
ncvtrace(int level, const char* fcn, const char* fmt, va_list ap)
226
0
{
227
0
    struct Frame* frame;
228
0
    if(!nclogginginitialized) ncloginit();
229
0
    if(nclog_global.tracelevel < 0) ncsetlogging(0);
230
0
    if(fcn != NULL) {
231
0
        frame = &nclog_global.frames[nclog_global.depth];
232
0
        frame->fcn = fcn;
233
0
        frame->level = level;
234
0
        frame->depth = nclog_global.depth;
235
0
    }
236
0
    if(level <= nclog_global.tracelevel) {
237
0
  if(fcn != NULL)
238
0
            fprintf(nclog_global.nclogstream,"%s: (%d): %s:","Enter",level,fcn);
239
0
        if(fmt != NULL)
240
0
            vfprintf(nclog_global.nclogstream, fmt, ap);
241
0
        fprintf(nclog_global.nclogstream, "\n" );
242
0
        fflush(nclog_global.nclogstream);
243
0
    }
244
0
    if(fcn != NULL) nclog_global.depth++;
245
0
}
246
247
int
248
ncuntrace(const char* fcn, int err, const char* fmt, ...)
249
0
{
250
0
    va_list args;
251
0
    struct Frame* frame;
252
0
    va_start(args, fmt);
253
0
    if(nclog_global.depth == 0) {
254
0
  fprintf(nclog_global.nclogstream,"*** Unmatched untrace: %s: depth==0\n",fcn);
255
0
  goto done;
256
0
    }
257
0
    nclog_global.depth--;
258
0
    frame = &nclog_global.frames[nclog_global.depth];
259
0
    if(frame->depth != nclog_global.depth || strcmp(frame->fcn,fcn) != 0) {
260
0
  fprintf(nclog_global.nclogstream,"*** Unmatched untrace: fcn=%s expected=%s\n",frame->fcn,fcn);
261
0
  goto done;
262
0
    }
263
0
    if(frame->level <= nclog_global.tracelevel) {
264
0
        fprintf(nclog_global.nclogstream,"%s: (%d): %s: ","Exit",frame->level,frame->fcn);
265
0
  if(err)
266
0
      fprintf(nclog_global.nclogstream,"err=(%d) '%s':",err,nc_strerror(err));
267
0
        if(fmt != NULL)
268
0
            vfprintf(nclog_global.nclogstream, fmt, args);
269
0
        fprintf(nclog_global.nclogstream, "\n" );
270
0
        fflush(nclog_global.nclogstream);
271
0
#ifdef HAVE_EXECINFO_H
272
0
        if(err != 0)
273
0
            ncbacktrace();
274
0
#endif
275
0
    }
276
0
done:
277
0
    va_end(args);
278
0
    if(err != 0)
279
0
        return ncbreakpoint(err);
280
0
    else
281
0
  return err;
282
0
}
283
284
int
285
ncthrow(int err,const char* file,int line)
286
0
{
287
0
    if(err == 0) return err;
288
0
    return ncbreakpoint(err);
289
0
}
290
291
int
292
ncbreakpoint(int err)
293
0
{
294
0
    return err;
295
0
}
296
297
#ifdef HAVE_EXECINFO_H
298
0
#define MAXSTACKDEPTH 100
299
void
300
ncbacktrace(void)
301
0
{
302
0
    int j, nptrs;
303
0
    void* buffer[MAXSTACKDEPTH];
304
0
    char **strings;
305
306
0
    if(getenv("NCBACKTRACE") == NULL) return;
307
0
    nptrs = backtrace(buffer, MAXSTACKDEPTH);
308
0
    strings = backtrace_symbols(buffer, nptrs);
309
0
    if (strings == NULL) {
310
0
        perror("backtrace_symbols");
311
0
        errno = 0;
312
0
  return;
313
0
    }
314
0
    fprintf(stderr,"Backtrace:\n");
315
0
    for(j = 0; j < nptrs; j++)
316
0
  fprintf(stderr,"%s\n", strings[j]);
317
0
    free(strings);
318
0
}
319
#endif
320
321
/**@}*/