Mstdlib-1.24.0
mstdlib_log.h
1
#ifndef MSTDLIB_LOG_H
2
#define MSTDLIB_LOG_H
3
4
#include <mstdlib/mstdlib.h>
5
#include <mstdlib/mstdlib_thread.h>
6
#include <mstdlib/mstdlib_io.h>
7
8
/*! \defgroup m_log Logging Subsystem
9
*
10
* \code{.c}
11
* #include <mstdlib/mstdlib_log.h>
12
* \endcode
13
*
14
* Example:
15
*
16
* \code{.c}
17
* #include <mstdlib/mstdlib_log.h>
18
*
19
* #define STREAM_QUEUE_SIZE (1500*1000) // 1.5 MB - small enough to cause a few drops, since all threads combined will
20
* // output about 1.7 MB of data
21
* #define FILE_QUEUE_SIZE (1500*1000) // 1.5 MB
22
* #define SYSLOG_QUEUE_SIZE (10*1000) // 10 KB
23
* #define CRIT_FREQ (500) // critical messages are sent every time message count hits a multiple of this number
24
* #define NUM_MSGS (10*1000) // total number of messages to send
25
*
26
* //#define FILE_DO_ARCHIVE //Uncomment to test file archiving.
27
* //#define ADD_LINE_END //Uncomment to add embedded line endings to log messages (tests multiline functionality).
28
*
29
* //#define DO_MEMBUF //Uncomment to test membuf.
30
*
31
*
32
* #ifdef FILE_DO_ARCHIVE
33
* static const char *archive_cmd = "bzip2 -f";
34
* static const char *archive_ext = ".bz2";
35
* #else
36
* static const char *archive_cmd = NULL;
37
* static const char *archive_ext = NULL;
38
* #endif
39
*
40
* static const M_bool flush_on_destroy = M_TRUE;
41
*
42
* typedef enum {
43
* TAG_1 = 1 << 0,
44
* TAG_2 = 1 << 1,
45
* TAG_3 = 1 << 2,
46
* CRIT_1 = 1 << 3,
47
* CRIT_2 = 1 << 4,
48
* CRIT_3 = 1 << 5
49
* } tags_t;
50
*
51
* static const char *tag_to_str(tags_t tag)
52
* {
53
* switch (tag) {
54
* case TAG_1: return "tag 1";
55
* case TAG_2: return "tag 2";
56
* case TAG_3: return "tag 3";
57
* case CRIT_1: return "CRITICAL 1";
58
* case CRIT_2: return "CRITICAL 2";
59
* case CRIT_3: return "CRITICAL 3";
60
* }
61
* return "unknown tag";
62
* }
63
*
64
*
65
* typedef struct {
66
* M_log_t *log;
67
* const char *msg;
68
* tags_t tag;
69
* tags_t crit_tag;
70
* } tdata_t;
71
*
72
* static void set(tdata_t *td, M_log_t *log, const char *msg, tags_t tag, tags_t crit_tag)
73
* {
74
* td->log = log;
75
* td->msg = msg;
76
* td->tag = tag;
77
* td->crit_tag = crit_tag;
78
* }
79
*
80
*
81
* static void prefix_cb(M_buf_t *buf, M_uint64 tag, void *prefix_thunk, void *msg_thunk)
82
* {
83
* (void)prefix_thunk;
84
* (void)msg_thunk;
85
* M_bprintf(buf, ": [%s]\t", tag_to_str((tags_t)tag));
86
* }
87
*
88
*
89
* static void *test_thread(void *arg)
90
* {
91
* tdata_t *td = arg;
92
* M_uint64 i;
93
* M_uint64 crit;
94
*
95
* crit = CRIT_FREQ;
96
* for (i=0; i<NUM_MSGS; i++) {
97
* M_log_error_t err;
98
* tags_t tag;
99
*
100
* //M_thread_sleep(10*1000); //Add 10 ms delay
101
*
102
* if (crit >= CRIT_FREQ) {
103
* tag = td->crit_tag;
104
* crit = 1;
105
* } else {
106
* tag = td->tag;
107
* ++crit;
108
* }
109
*
110
* err = M_log_printf(td->log, tag, NULL,
111
* #ifdef ADD_LINE_END
112
* "%s --\n %llu",
113
* #else
114
* "%s -- %llu",
115
* #endif
116
* td->msg, i);
117
*
118
* if (err != M_LOG_SUCCESS) {
119
* M_fprintf(stderr, "Error writing log message: %s\n", M_log_err_to_str(err));
120
* }
121
* }
122
*
123
* return NULL;
124
* }
125
*
126
*
127
* int main(int argc, char *argv[])
128
* {
129
* M_log_t *log;
130
* M_log_error_t res;
131
* M_log_module_t *mod_stream;
132
* M_log_module_t *mod_syslog;
133
* M_log_module_t *mod_file;
134
* #ifdef DO_MEMBUF
135
* M_log_module_t *mod_membuf;
136
* M_fs_file_t *membuf_out;
137
* M_buf_t *membuf;
138
* #endif
139
* M_thread_attr_t *attr;
140
* M_threadid_t t1, t2, t3;
141
* tdata_t data1, data2, data3;
142
*
143
* (void)argc;
144
* (void)argv;
145
*
146
* // Set up the log.
147
* log = M_log_create(M_LOG_LINE_END_NATIVE, flush_on_destroy, NULL);
148
* M_log_set_time_format(log, "[%a %D %Y %H:%m:%s:%u %z]");
149
* M_log_set_tag_name(log, TAG_1, "tag_1_name");
150
* M_log_set_tag_name(log, TAG_2, "tag_2_name");
151
* M_log_set_tag_name(log, TAG_3, "tag_3_name");
152
* M_log_set_tag_name(log, CRIT_1, "crit_1_name");
153
* M_log_set_tag_name(log, CRIT_2, "crit_2_name");
154
* M_log_set_tag_name(log, CRIT_3, "crit_3_name");
155
*
156
* // Set up the stream module.
157
* res = M_log_module_add_stream(log, M_STREAM_STDOUT, STREAM_QUEUE_SIZE, &mod_stream);
158
* //res = M_log_module_add_nslog(log, STREAM_QUEUE_SIZE, &mod_stream);
159
* if (res != M_LOG_SUCCESS) {
160
* M_fprintf(stderr, "Could not add stream module: %s\n", M_log_err_to_str(res));
161
* } else {
162
* M_log_module_set_accepted_tags(log, mod_stream, TAG_1 | TAG_2 | TAG_3 | CRIT_1 | CRIT_2 | CRIT_3);
163
*
164
* M_log_module_set_prefix(log, mod_stream, prefix_cb, NULL, NULL);
165
* }
166
*
167
* // Set up the file module.
168
* res = M_log_module_add_file(log, "~/Tmp/logs/testing.log", 15, 150000, 0, FILE_QUEUE_SIZE, archive_cmd, archive_ext, &mod_file);
169
* if (res != M_LOG_SUCCESS) {
170
* M_fprintf(stderr, "Could not add file module: %s\n", M_log_err_to_str(res));
171
* } else {
172
* M_log_module_set_accepted_tags(log, mod_file, TAG_1 | TAG_2 | TAG_3 | CRIT_1 | CRIT_2 | CRIT_3);
173
*
174
* M_log_module_set_prefix(log, mod_file, prefix_cb, NULL, NULL);
175
* }
176
*
177
*
178
* // Set up the syslog module.
179
* res = M_log_module_add_syslog(log, "log_example", M_SYSLOG_FACILITY_LOCAL5, SYSLOG_QUEUE_SIZE, &mod_syslog);
180
*
181
* if (res != M_LOG_SUCCESS) {
182
* M_fprintf(stderr, "Could not add syslog module: %s\n", M_log_err_to_str(res));
183
* } else {
184
* M_log_module_set_accepted_tags(log, mod_syslog, CRIT_1 | CRIT_2 | CRIT_3);
185
*
186
* M_log_module_set_prefix(log, mod_syslog, prefix_cb, NULL, NULL);
187
*
188
* M_log_module_syslog_set_tag_priority(log, mod_syslog, CRIT_1 | CRIT_2, M_SYSLOG_WARNING);
189
*
190
* M_log_module_syslog_set_tag_priority(log, mod_syslog, CRIT_3, M_SYSLOG_CRIT);
191
* }
192
*
193
* // Do an emergency call (just to see if it really works).
194
* M_log_emergency(log, "RED ALERT! WOOT WOOT WOOT\r\n");
195
*
196
* // Launch three test threads that spam the logger with a bunch of messages.
197
* set(&data1, log, "data1", TAG_1, CRIT_1);
198
* set(&data2, log, "data2", TAG_2, CRIT_2);
199
* set(&data3, log, "data3", TAG_3, CRIT_3);
200
*
201
* attr = M_thread_attr_create();
202
* M_thread_attr_set_create_joinable(attr, M_TRUE);
203
*
204
* t1 = M_thread_create(attr, test_thread, &data1);
205
* t2 = M_thread_create(attr, test_thread, &data2);
206
* t3 = M_thread_create(attr, test_thread, &data3);
207
*
208
* M_thread_attr_destroy(attr);
209
*
210
* #ifdef DO_MEMBUF
211
* // Wait a little before we add the membuf module.
212
* M_thread_sleep(50*1000); // 50 ms
213
*
214
* res = M_log_module_add_membuf(log, 400*1000, 60*1000, NULL, NULL, &mod_membuf);
215
* if (res != M_LOG_SUCCESS) {
216
* M_fprintf(stderr, "Could not add membuf module: %s\n", M_log_err_to_str(res));
217
* } else {
218
* M_log_module_set_accepted_tags(log, mod_membuf, TAG_1 | CRIT_2);
219
*
220
* M_log_module_set_prefix(log, mod_membuf, prefix_cb, NULL, NULL);
221
* }
222
* #endif
223
*
224
* // Do a suspend/resume operation.
225
* M_log_suspend(log);
226
* M_thread_sleep(500); // sleep for 0.5 ms
227
* M_log_resume(log, NULL);
228
*
229
* // Wait until all three threads are done spamming.
230
* M_thread_join(t1, NULL);
231
* M_thread_join(t2, NULL);
232
* M_thread_join(t3, NULL);
233
*
234
* #ifdef DO_MEMBUF
235
* // Pull contents of membuf, dump to file.
236
* M_log_module_take_membuf(log, mod_membuf, &membuf);
237
*
238
* M_fs_file_open(&membuf_out, "~/Tmp/logs/log_membuf.txt", 0, M_FS_FILE_MODE_WRITE | M_FS_FILE_MODE_OVERWRITE, NULL);
239
* M_fs_file_write(membuf_out, (const unsigned char *)M_buf_peek(membuf), M_buf_len(membuf),
240
* NULL, M_FS_FILE_RW_NORMAL);
241
* M_fs_file_close(membuf_out);
242
*
243
* M_buf_cancel(membuf);
244
* #endif
245
*
246
* // Destroy the log. If internal workers are still processing messages, this will wait until they finish outputting
247
* // their internal message queues and exit. This ensures that we don't see any memory leaks at process exit.
248
* //
249
* // Wait up to five seconds for threads to finish writing.
250
* M_log_destroy_blocking(log, 5000);
251
*
252
* return EXIT_SUCCESS;
253
* }
254
* \endcode
255
*
256
* Example (simple logging to a file):
257
*
258
* \code{.c}
259
* #include <mstdlib/mstdlib.h>
260
* #include <mstdlib/mstdlib_log.h>
261
* #include <mstdlib/mstdlib_thread.h>
262
*
263
* typedef enum {
264
* TAG_1 = 1 << 0
265
* } tags_t;
266
*
267
* int main(int argc, char **argv)
268
* {
269
* M_log_t *log;
270
* M_log_module_t *mod_file;
271
* M_log_error_t res;
272
* size_t i;
273
*
274
* log = M_log_create(M_LOG_LINE_END_NATIVE, M_TRUE, NULL);
275
* M_log_set_tag_name(log, TAG_1, "tag_1_name");
276
* // Use /dev/stdout (*nix/macOS) as a pretend file. We could have specified an actual file that
277
* // exists or not but this is a good way to see what's happening.
278
* res = M_log_module_add_file(log, "/dev/stdout", 15, 150000, 0, 150000, NULL, NULL, &mod_file);
279
* if (res != M_LOG_SUCCESS) {
280
* M_fprintf(stderr, "Could not add file module: %s\n", M_log_err_to_str(res));
281
* M_log_destroy(log);
282
* return 1;
283
* } else {
284
* M_log_module_set_accepted_tags(log, mod_file, TAG_1);
285
* }
286
*
287
* for (i=0; i<12; i++) {
288
* M_log_printf(log, TAG_1, NULL, "Test.. %zu ...\n", i+1);
289
* M_thread_sleep(10*10000);
290
* }
291
*
292
* M_log_destroy_blocking(log, 5000);
293
* return 0;
294
* }
295
* \endcode
296
*/
297
298
#include <mstdlib/log/m_async_writer.h>
299
#include <mstdlib/log/m_log.h>
300
301
#endif
/* MSTDLIB_LOG_H */
302
include
mstdlib
mstdlib_log.h
Generated on Tue Aug 15 2023 12:53:09 for Mstdlib-1.24.0 by
1.9.4