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