Create unittest for i18n_noop[s]
[libi2ncommon] / src / tracefunc.cpp
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
b6fb82a2
RP
20/** @file
21 * @brief implementation of tracing functionality.
22 *
84eef65a 23 * @copyright © Copyright 2008,2011 by Intra2net AG
f4fcef65
TJ
24 *
25 * Every thread gets its' own ScopeTracker stack via TLS (thread local storage)
b6fb82a2 26 *
b6fb82a2
RP
27 */
28
29#include "tracefunc.hpp"
30
31#include <list>
32#include <vector>
33#include <sstream>
f4fcef65 34#include <boost/thread/tss.hpp>
b6fb82a2 35
12481159
CH
36#include <stringfunc.hxx>
37
b6fb82a2
RP
38namespace I2n
39{
40namespace Tracer
41{
42
43using Logger::GlobalLogger;
44
f4fcef65
TJ
45class PerThreadContainer
46{
47public:
84eef65a 48 typedef std::vector< ScopeTracker* > ScopeTrackerList;
f4fcef65
TJ
49
50 /// List of currently active scope trackers
51 ScopeTrackerList scope_tracker_list;
52
53 /// Precomputed indent levels
54 std::vector< std::string > indents;
55};
b6fb82a2
RP
56
57namespace
58{
59
f4fcef65
TJ
60/// Internal TLS (thread local storage) data container
61boost::thread_specific_ptr<PerThreadContainer> thread_container;
b6fb82a2 62
f4fcef65
TJ
63/**
64 * Helper function to retrieve TLS pointer.
65 * Initializes the pointer if called for the first time.
66 * @return Pointer to the per thread container
67 */
68static PerThreadContainer *TLS_get_container()
69{
70 // First call? Construct options container
71 if (thread_container.get() == NULL)
72 thread_container.reset(new PerThreadContainer());
b6fb82a2 73
f4fcef65 74 PerThreadContainer *per_thread = thread_container.get();
b6fb82a2 75
f4fcef65
TJ
76 return per_thread;
77}
b6fb82a2
RP
78
79/**
80 * @brief ensures indent level string to exist up to the desired level.
81 * @param level the desired indent level.
82 */
29bc7241 83static void ensure_indent_level(PerThreadContainer *per_thread, unsigned int level)
b6fb82a2 84{
f4fcef65
TJ
85 // First initialization?
86 if (per_thread->indents.empty())
87 {
88 per_thread->indents.reserve(10);
89 if (level < 10)
90 level = 10;
91
92 per_thread->indents.push_back("");
93 }
94
95 while (per_thread->indents.size() <= level)
b6fb82a2 96 {
f4fcef65 97 per_thread->indents.push_back( per_thread->indents.back() + " " );
b6fb82a2
RP
98 }
99} // eo ensure_indent_level(int)
100
b6fb82a2
RP
101} // eo namespace <anonymous>
102
103
104/*
105** implementation of ScopeTracker
106*/
107
108/**
109 * @brief constructor. initializes object with a source location and emits a ENTER message.
110 * @param loc the source location.
111 *
112 * the message is indented according to the current depth of nested ScopeTracker instances.
113 */
114ScopeTracker::ScopeTracker(
115 const SourceLocation& loc)
f4fcef65
TJ
116 : Location(loc)
117 , Depth(0)
118 , FuncDepth(0)
119 , PerThread(TLS_get_container())
b6fb82a2 120{
f4fcef65 121 if (!PerThread->scope_tracker_list.empty())
b6fb82a2 122 {
f4fcef65 123 ScopeTracker* last_tracker= PerThread->scope_tracker_list.back();
b6fb82a2
RP
124 if (Location)
125 {
126 if (last_tracker->Location
127 && last_tracker->Location.File == Location.File
128 && last_tracker->Location.FunctionName == Location.FunctionName)
129 {
130 FuncDepth= last_tracker->FuncDepth+1;
131 }
132 }
133 Depth= last_tracker->Depth + 1;
134 }
f4fcef65
TJ
135 ensure_indent_level(PerThread, Depth);
136 PerThread->scope_tracker_list.push_back(this);
fdd09ae0 137
b6fb82a2
RP
138 // spit a message
139 if (Logger::has_log_level(Logger::LogLevel::Debug))
140 {
fdd09ae0 141 GlobalLogger.debug() << PerThread->indents[Depth] << "ENTER " << get_tag();
b6fb82a2
RP
142 }
143} // eo ScopeTrcaker::ScopeTracker(const SourceLocation&)
144
145
146/**
fdd09ae0
CH
147 * @brief create Tag if empty; return reference to it
148 *
149 * Moved this from constructor into own function to avoid creating Tag if it is
150 * not required (i.e. log level is not DEBUG) but still create it only once and
151 * ensure it is available if log level changes inside tracked function
152 */
153std::string& ScopeTracker::get_tag()
154{
155 if (Tag.empty())
156 {
157 if (Location.FunctionName.empty())
158 {
159 Tag = "<unknown> (global scope?)";
160 }
161 else
162 {
163 std::ostringstream ostr;
164 ostr << shorten_stl_types(Location.FunctionName);
165 if (FuncDepth>0)
166 {
167 ostr << "#" << FuncDepth+1;
168 }
169 Tag= ostr.str();
170 }
171 }
172 return Tag;
173}
174
175
176/**
b6fb82a2
RP
177 * @brief destructor. emits a LEAVE message.
178 *
179 *
180 */
181ScopeTracker::~ScopeTracker()
182{
183 // spit a message
184 if (Logger::has_log_level(Logger::LogLevel::Debug))
185 {
fdd09ae0 186 GlobalLogger.debug() << PerThread->indents[Depth] << "LEAVE " << get_tag();
b6fb82a2 187 }
f4fcef65 188 if (PerThread->scope_tracker_list.empty())
b6fb82a2
RP
189 {
190 return;
191 }
f4fcef65 192 if (PerThread->scope_tracker_list.back() == this)
b6fb82a2 193 {
f4fcef65 194 PerThread->scope_tracker_list.pop_back();
b6fb82a2
RP
195 }
196 else
197 {
198 // oh hell, this should never be the case!
199 //TODO
200 GlobalLogger.error() << "inconsistency detected in scope tracker";
201 }
202} // eo ScopeTracker::~ScopeTracker()
203
204
205
206
207} // eo namespace Tracer
208} // eo namespace I2n