Switch license from Intranator license to GPLv2 + linking exception (ACKed by Steffen)
[libi2ncommon] / src / tracefunc.cpp
1 /*
2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
4
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
7
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
13
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
16
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
19 */
20 /** @file
21  * @brief implementation of tracing functionality.
22  *
23  * @copyright © Copyright 2008 by Intra2net AG
24  *
25  * @note This module is not thread safe!
26  * @todo make this module thread safe (only useful when we can use threads...)
27  */
28
29 #include "tracefunc.hpp"
30
31 #include <list>
32 #include <vector>
33 #include <sstream>
34
35
36 namespace I2n
37 {
38 namespace Tracer
39 {
40
41 using Logger::GlobalLogger;
42
43
44 namespace
45 {
46
47 typedef std::list< ScopeTracker* > ScopeTrackerList;
48
49 ScopeTrackerList scope_tracker_list;
50
51
52 std::vector< std::string > indents;
53
54
55 /**
56  * @brief ensures indent level string to exist up to the desired level.
57  * @param level the desired indent level.
58  */
59 void ensure_indent_level(int level)
60 {
61    while (indents.size() <= level)
62    {
63       indents.push_back( indents.back() + "  " );
64    }
65 } // eo ensure_indent_level(int)
66
67
68 /**
69  * @brief module initializer.
70  */
71 class __Initializer
72 {
73    public:
74       __Initializer()
75       {
76          // pre initialize indent strings:
77          indents.clear();
78          indents.reserve(10);
79          indents.push_back("");
80          for(int i=10; i-->0;)
81          {
82             indents.push_back( indents.back() + "  " );
83          }
84       }
85 } __initializer;
86
87
88 } // eo namespace <anonymous>
89
90
91 /*
92 ** implementation of ScopeTracker
93 */
94
95 /**
96  * @brief constructor. initializes object with a source location and emits a ENTER message.
97  * @param loc the source location.
98  *
99  * the message is indented according to the current depth of nested ScopeTracker instances.
100  */
101 ScopeTracker::ScopeTracker(
102     const SourceLocation& loc)
103 : Location(loc)
104 , Depth(0)
105 , FuncDepth(0)
106 {
107    if (!scope_tracker_list.empty())
108    {
109       ScopeTracker* last_tracker= scope_tracker_list.back();
110       if (Location)
111       {
112          if (last_tracker->Location
113              && last_tracker->Location.File == Location.File
114              && last_tracker->Location.FunctionName == Location.FunctionName)
115          {
116             FuncDepth= last_tracker->FuncDepth+1;
117          }
118       }
119       Depth= last_tracker->Depth + 1;
120    }
121    ensure_indent_level(Depth);
122    scope_tracker_list.push_back(this);
123    {
124       std::ostringstream ostr;
125       if (Location.FunctionName.empty())
126       {
127          ostr << "<unknown> (global scope?)";
128       }
129       else
130       {
131          ostr << Location.FunctionName;
132          if (FuncDepth>0)
133          {
134             ostr << "#" << FuncDepth+1;
135          }
136       }
137       Tag= ostr.str();
138    }
139    // spit a message
140    if (Logger::has_log_level(Logger::LogLevel::Debug))
141    {
142       GlobalLogger.debug() << indents[Depth] << "ENTER " << Tag;
143    }
144 } // eo ScopeTrcaker::ScopeTracker(const SourceLocation&)
145
146
147 /**
148  * @brief destructor. emits a LEAVE message.
149  *
150  *
151  */
152 ScopeTracker::~ScopeTracker()
153 {
154    // spit a message
155    if (Logger::has_log_level(Logger::LogLevel::Debug))
156    {
157       GlobalLogger.debug() << indents[Depth] << "LEAVE " << Tag;
158    }
159    if (scope_tracker_list.empty())
160    {
161       return;
162    }
163    if (scope_tracker_list.back() == this)
164    {
165       scope_tracker_list.pop_back();
166    }
167    else
168    {
169       // oh hell, this should never be the case!
170       //TODO
171       GlobalLogger.error() << "inconsistency detected in scope tracker";
172    }
173 } // eo ScopeTracker::~ScopeTracker()
174
175
176
177
178 } // eo namespace Tracer
179 } // eo namespace I2n