File: logging.h

package info (click to toggle)
aws-crt-python 0.20.4%2Bdfsg-1~bpo12%2B1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-backports
  • size: 72,656 kB
  • sloc: ansic: 381,805; python: 23,008; makefile: 6,251; sh: 4,536; cpp: 699; ruby: 208; java: 77; perl: 73; javascript: 46; xml: 11
file content (359 lines) | stat: -rw-r--r-- 13,144 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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
#ifndef AWS_COMMON_LOGGING_H
#define AWS_COMMON_LOGGING_H

/**
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

#include <aws/common/atomics.h>
#include <aws/common/common.h>
#include <aws/common/thread.h>

AWS_PUSH_SANE_WARNING_LEVEL

#define AWS_LOG_LEVEL_NONE 0
#define AWS_LOG_LEVEL_FATAL 1
#define AWS_LOG_LEVEL_ERROR 2
#define AWS_LOG_LEVEL_WARN 3
#define AWS_LOG_LEVEL_INFO 4
#define AWS_LOG_LEVEL_DEBUG 5
#define AWS_LOG_LEVEL_TRACE 6

/**
 * Controls what log calls pass through the logger and what log calls get filtered out.
 * If a log level has a value of X, then all log calls using a level <= X will appear, while
 * those using a value > X will not occur.
 *
 * You can filter both dynamically (by setting the log level on the logger object) or statically
 * (by defining AWS_STATIC_LOG_LEVEL to be an appropriate integer module-wide).  Statically filtered
 * log calls will be completely compiled out but require a rebuild if you want to get more detail
 * about what's happening.
 */
enum aws_log_level {
    AWS_LL_NONE = AWS_LOG_LEVEL_NONE,
    AWS_LL_FATAL = AWS_LOG_LEVEL_FATAL,
    AWS_LL_ERROR = AWS_LOG_LEVEL_ERROR,
    AWS_LL_WARN = AWS_LOG_LEVEL_WARN,
    AWS_LL_INFO = AWS_LOG_LEVEL_INFO,
    AWS_LL_DEBUG = AWS_LOG_LEVEL_DEBUG,
    AWS_LL_TRACE = AWS_LOG_LEVEL_TRACE,

    AWS_LL_COUNT
};

/**
 * Log subject is a way of designating the topic of logging.
 *
 * The general idea is to support a finer-grained approach to log level control.  The primary use case
 * is for situations that require more detailed logging within a specific domain, where enabling that detail
 * globally leads to an untenable flood of information.
 *
 * For example, enable TRACE logging for tls-related log statements (handshake binary payloads), but
 * only WARN logging everywhere else (because http payloads would blow up the log files).
 *
 * Log subject is an enum similar to aws error: each library has its own value-space and someone is
 * responsible for registering the value <-> string connections.
 */
typedef uint32_t aws_log_subject_t;

/* Each library gets space for 2^^10 log subject entries */
enum {
    AWS_LOG_SUBJECT_STRIDE_BITS = 10,
};
#define AWS_LOG_SUBJECT_STRIDE (1U << AWS_LOG_SUBJECT_STRIDE_BITS)
#define AWS_LOG_SUBJECT_BEGIN_RANGE(x) ((x)*AWS_LOG_SUBJECT_STRIDE)
#define AWS_LOG_SUBJECT_END_RANGE(x) (((x) + 1) * AWS_LOG_SUBJECT_STRIDE - 1)

struct aws_log_subject_info {
    aws_log_subject_t subject_id;
    const char *subject_name;
    const char *subject_description;
};

#define DEFINE_LOG_SUBJECT_INFO(id, name, desc)                                                                        \
    { .subject_id = (id), .subject_name = (name), .subject_description = (desc) }

struct aws_log_subject_info_list {
    struct aws_log_subject_info *subject_list;
    size_t count;
};

enum aws_common_log_subject {
    AWS_LS_COMMON_GENERAL = AWS_LOG_SUBJECT_BEGIN_RANGE(AWS_C_COMMON_PACKAGE_ID),
    AWS_LS_COMMON_TASK_SCHEDULER,
    AWS_LS_COMMON_THREAD,
    AWS_LS_COMMON_MEMTRACE,
    AWS_LS_COMMON_XML_PARSER,
    AWS_LS_COMMON_IO,
    AWS_LS_COMMON_BUS,
    AWS_LS_COMMON_TEST,
    AWS_LS_COMMON_JSON_PARSER,

    AWS_LS_COMMON_LAST = AWS_LOG_SUBJECT_END_RANGE(AWS_C_COMMON_PACKAGE_ID)
};

struct aws_logger;
struct aws_log_formatter;
struct aws_log_channel;
struct aws_log_writer;

#ifdef _MSC_VER
#    pragma warning(push)
#    pragma warning(disable : 4623) /* default constructor was implicitly defined as deleted */
#    pragma warning(disable : 4626) /* assignment operator was implicitly defined as deleted */
#    pragma warning(disable : 5027) /* move assignment operator was implicitly defined as deleted */
#endif

/**
 * We separate the log level function from the log call itself so that we can do the filter check in the macros (see
 * below)
 *
 * By doing so, we make it so that the variadic format arguments are not even evaluated if the filter check does not
 * succeed.
 */
struct aws_logger_vtable {
    int (*const log)(
        struct aws_logger *logger,
        enum aws_log_level log_level,
        aws_log_subject_t subject,
        const char *format,
        ...)
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
        __attribute__((format(printf, 4, 5)))
#endif /* non-ms compilers: TODO - find out what versions format support was added in */
        ;
    enum aws_log_level (*const get_log_level)(struct aws_logger *logger, aws_log_subject_t subject);
    void (*const clean_up)(struct aws_logger *logger);
    int (*set_log_level)(struct aws_logger *logger, enum aws_log_level);
};

#ifdef _MSC_VER
#    pragma warning(pop)
#endif

struct aws_logger {
    struct aws_logger_vtable *vtable;
    struct aws_allocator *allocator;
    void *p_impl;
};

/**
 * The base formatted logging macro that all other formatted logging macros resolve to.
 * Checks for a logger and filters based on log level.
 */
#define AWS_LOGF(log_level, subject, ...)                                                                              \
    do {                                                                                                               \
        AWS_ASSERT(log_level > 0);                                                                                     \
        struct aws_logger *logger = aws_logger_get();                                                                  \
        if (logger != NULL && logger->vtable->get_log_level(logger, (subject)) >= (log_level)) {                       \
            logger->vtable->log(logger, log_level, subject, __VA_ARGS__);                                              \
        }                                                                                                              \
    } while (0)
/**
 * Unconditional logging macro that takes a logger and does not do a level check or a null check.  Intended for
 * situations when you need to log many things and do a single manual level check before beginning.
 */
#define AWS_LOGUF(logger, log_level, subject, ...)                                                                     \
    { logger->vtable->log(logger, log_level, subject, __VA_ARGS__); }

/**
 * LOGF_<level> variants for each level.  These are what should be used directly to do all logging.
 *
 * i.e.
 *
 * LOGF_FATAL("Device \"%s\" not found", device->name);
 *
 *
 * Later we will likely expose Subject-aware variants
 */
#if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_FATAL)
#    define AWS_LOGF_FATAL(subject, ...) AWS_LOGF(AWS_LL_FATAL, subject, __VA_ARGS__)
#else
#    define AWS_LOGF_FATAL(subject, ...)
#endif

#if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_ERROR)
#    define AWS_LOGF_ERROR(subject, ...) AWS_LOGF(AWS_LL_ERROR, subject, __VA_ARGS__)
#else
#    define AWS_LOGF_ERROR(subject, ...)
#endif

#if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_WARN)
#    define AWS_LOGF_WARN(subject, ...) AWS_LOGF(AWS_LL_WARN, subject, __VA_ARGS__)
#else
#    define AWS_LOGF_WARN(subject, ...)
#endif

#if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_INFO)
#    define AWS_LOGF_INFO(subject, ...) AWS_LOGF(AWS_LL_INFO, subject, __VA_ARGS__)
#else
#    define AWS_LOGF_INFO(subject, ...)
#endif

#if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_DEBUG)
#    define AWS_LOGF_DEBUG(subject, ...) AWS_LOGF(AWS_LL_DEBUG, subject, __VA_ARGS__)
#else
#    define AWS_LOGF_DEBUG(subject, ...)
#endif

#if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_TRACE)
#    define AWS_LOGF_TRACE(subject, ...) AWS_LOGF(AWS_LL_TRACE, subject, __VA_ARGS__)
#else
#    define AWS_LOGF_TRACE(subject, ...)
#endif

/*
 * Standard logger implementation composing three sub-components:
 *
 * The formatter takes var args input from the user and produces a formatted log line
 * The writer takes a formatted log line and outputs it somewhere
 * The channel is the transport between the two
 */
struct aws_logger_pipeline {
    struct aws_log_formatter *formatter;
    struct aws_log_channel *channel;
    struct aws_log_writer *writer;
    struct aws_allocator *allocator;
    struct aws_atomic_var level;
};

/**
 * Options for aws_logger_init_standard().
 * Set `filename` to open a file for logging and close it when the logger cleans up.
 * Set `file` to use a file that is already open, such as `stderr` or `stdout`.
 */
struct aws_logger_standard_options {
    enum aws_log_level level;
    const char *filename;
    FILE *file;
};

AWS_EXTERN_C_BEGIN

/**
 * Sets the aws logger used globally across the process.  Not thread-safe.  Must only be called once.
 */
AWS_COMMON_API
void aws_logger_set(struct aws_logger *logger);

/**
 * Gets the aws logger used globally across the process.
 */
AWS_COMMON_API
struct aws_logger *aws_logger_get(void);

/**
 * Gets the aws logger used globally across the process if the logging level is at least the inputted level.
 *
 * @param subject log subject to perform the level check versus, not currently used
 * @param level logging level to check against in order to return the logger
 * @return the current logger if the current logging level is at or more detailed then the supplied logging level
 */
AWS_COMMON_API
struct aws_logger *aws_logger_get_conditional(aws_log_subject_t subject, enum aws_log_level level);

/**
 * Cleans up all resources used by the logger; simply invokes the clean_up v-function
 */
AWS_COMMON_API
void aws_logger_clean_up(struct aws_logger *logger);

/**
 * Sets the current logging level for the logger.  Loggers are not require to support this.
 * @param logger logger to set the log level for
 * @param level new log level for the logger
 * @return AWS_OP_SUCCESS if the level was successfully set, AWS_OP_ERR otherwise
 */
AWS_COMMON_API
int aws_logger_set_log_level(struct aws_logger *logger, enum aws_log_level level);

/**
 * Converts a log level to a c-string constant.  Intended primarily to support building log lines that
 * include the level in them, i.e.
 *
 * [ERROR] 10:34:54.642 01-31-19 - Json parse error....
 */
AWS_COMMON_API
int aws_log_level_to_string(enum aws_log_level log_level, const char **level_string);

/**
 * Converts a c-string constant to a log level value.  Uses case-insensitive comparison
 * and simply iterates all possibilities until a match or nothing remains.  If no match
 * is found, AWS_OP_ERR is returned.
 */
AWS_COMMON_API
int aws_string_to_log_level(const char *level_string, enum aws_log_level *log_level);

/**
 * Converts an aws_thread_id_t to a c-string.  For portability, aws_thread_id_t
 * must not be printed directly.  Intended primarily to support building log
 * lines that include the thread id in them.  The parameter `buffer` must
 * point-to a char buffer of length `bufsz == AWS_THREAD_ID_T_REPR_BUFSZ`.  The
 * thread id representation is returned in `buffer`.
 */
AWS_COMMON_API
int aws_thread_id_t_to_string(aws_thread_id_t thread_id, char *buffer, size_t bufsz);

/**
 * Get subject name from log subject.
 */
AWS_COMMON_API
const char *aws_log_subject_name(aws_log_subject_t subject);

/**
 * Connects log subject strings with log subject integer values
 */
AWS_COMMON_API
void aws_register_log_subject_info_list(struct aws_log_subject_info_list *log_subject_list);

/**
 * Disconnects log subject strings with log subject integer values
 */
AWS_COMMON_API
void aws_unregister_log_subject_info_list(struct aws_log_subject_info_list *log_subject_list);

/*
 * Initializes a pipeline logger that is built from the default formatter, a background thread-based channel, and
 * a file writer.  The default logger in almost all circumstances.
 */
AWS_COMMON_API
int aws_logger_init_standard(
    struct aws_logger *logger,
    struct aws_allocator *allocator,
    struct aws_logger_standard_options *options);

/*
 * Initializes a pipeline logger from components that have already been initialized.  This is not an ownership transfer.
 * After the pipeline logger is cleaned up, the components will have to manually be cleaned up by the user.
 */
AWS_COMMON_API
int aws_logger_init_from_external(
    struct aws_logger *logger,
    struct aws_allocator *allocator,
    struct aws_log_formatter *formatter,
    struct aws_log_channel *channel,
    struct aws_log_writer *writer,
    enum aws_log_level level);

/*
 * Pipeline logger vtable for custom configurations
 */
AWS_COMMON_API
extern struct aws_logger_vtable g_pipeline_logger_owned_vtable;

/*
 * Initializes a logger that does not perform any allocation during logging.  Log lines larger than the internal
 * constant are truncated.  Formatting matches the standard logger.  Used for memory tracing logging.
 * If no file or filename is set in the aws_logger_standard_options, then it will use stderr.
 */
AWS_COMMON_API
int aws_logger_init_noalloc(
    struct aws_logger *logger,
    struct aws_allocator *allocator,
    struct aws_logger_standard_options *options);

AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL

#endif /* AWS_COMMON_LOGGING_H */