1 // The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
2
3 /*
4
5 This is a somewhat complex example illustrating the use of the logger object
6 from the dlib C++ Library. It will demonstrate using multiple loggers and threads.
7
8
9 The output of this program looks like this:
10 0 INFO [0] example: This is an informational message.
11 0 WARN [0] example: The variable is bigger than 4! Its value is 8
12 0 INFO [0] example: make two threads
13 0 WARN [0] example.test_class: warning! someone called warning()!
14 0 INFO [0] example: we are going to sleep for half a second.
15 0 INFO [1] example.thread: entering our thread
16 0 WARN [1] example.test_class: warning! someone called warning()!
17 0 INFO [2] example.thread: entering our thread
18 0 WARN [2] example.test_class: warning! someone called warning()!
19 203 INFO [1] example.thread: exiting our thread
20 203 INFO [2] example.thread: exiting our thread
21 503 INFO [0] example: we just woke up
22 503 INFO [0] example: program ending
23
24
25 */
26
27
28 #include <dlib/logger.h>
29 #include <dlib/misc_api.h>
30 #include <dlib/threads.h>
31
32 using namespace dlib;
33
34 /*
35 Here we create three loggers. Note that it is the case that:
36 - logp.is_child_of(logp) == true
37 - logt.is_child_of(logp) == true
38 - logc.is_child_of(logp) == true
39
40 logp is the child of itself because all loggers are their own children :) But the other
41 two are child loggers of logp because their names start with logp.name() + "." which means
42 that whenever you set a property on a logger it will also set that same property on all of
43 the logger's children.
44 */
45 logger logp("example");
46 logger logt("example.thread");
47 logger logc("example.test_class");
48
49 class test
50 {
51 public:
test()52 test ()
53 {
54 // this message won't get logged because LINFO is too low
55 logc << LINFO << "constructed a test object";
56 }
57
~test()58 ~test ()
59 {
60 // this message won't get logged because LINFO is too low
61 logc << LINFO << "destructed a test object";
62 }
63
warning()64 void warning ()
65 {
66 logc << LWARN << "warning! someone called warning()!";
67 }
68 };
69
thread(void *)70 void thread (void*)
71 {
72 logt << LINFO << "entering our thread";
73
74
75 test mytest;
76 mytest.warning();
77
78 dlib::sleep(200);
79
80 logt << LINFO << "exiting our thread";
81 }
82
83
setup_loggers()84 void setup_loggers (
85 )
86 {
87 // Create a logger that has the same name as our root logger logp. This isn't very useful in
88 // this example program but if you had loggers defined in other files then you might not have
89 // easy access to them when starting up your program and setting log levels. This mechanism
90 // allows you to manipulate the properties of any logger so long as you know its name.
91 logger temp_log("example");
92
93 // For this example I don't want to log debug messages so I'm setting the logging level of
94 // All our loggers to LINFO. Note that this statement sets all three of our loggers to this
95 // logging level because they are all children of temp_log.
96 temp_log.set_level(LINFO);
97
98
99 // In addition I only want the example.test_class to print LWARN or higher messages so I'm going
100 // to set that here too. Note that we set this value after calling temp_log.set_level(). If we
101 // did it the other way around the set_level() call on temp_log would set logc_temp.level() and
102 // logc.level() back to LINFO since temp_log is a parent of logc_temp.
103 logger logc_temp("example.test_class");
104 logc_temp.set_level(LWARN);
105
106
107 // Finally, note that you can also configure your loggers from a text config file.
108 // See the documentation for the configure_loggers_from_file() function for details.
109 }
110
main()111 int main()
112 {
113 setup_loggers();
114
115 // print our first message. It will go to cout because that is the default.
116 logp << LINFO << "This is an informational message.";
117
118 int variable = 8;
119
120 // Here is a debug message. It won't print though because its log level is too low (it is below LINFO).
121 logp << LDEBUG << "The integer variable is set to " << variable;
122
123
124 if (variable > 4)
125 logp << LWARN << "The variable is bigger than 4! Its value is " << variable;
126
127 logp << LINFO << "make two threads";
128 create_new_thread(thread,0);
129 create_new_thread(thread,0);
130
131 test mytest;
132 mytest.warning();
133
134 logp << LINFO << "we are going to sleep for half a second.";
135 // sleep for half a second
136 dlib::sleep(500);
137 logp << LINFO << "we just woke up";
138
139
140
141 logp << LINFO << "program ending";
142
143
144 // It is also worth pointing out that the logger messages are atomic. This means, for example, that
145 // in the above log statements that involve a string literal and a variable, no other thread can
146 // come in and print a log message in-between the literal string and the variable. This is good
147 // because it means your messages don't get corrupted. However, this also means that you shouldn't
148 // make any function calls inside a logging statement if those calls might try to log a message
149 // themselves since the atomic nature of the logger would cause your application to deadlock.
150 }
151
152
153
154