Fix signed/unsigned comparison
[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
RP
35
36namespace I2n
37{
38namespace Tracer
39{
40
41using Logger::GlobalLogger;
42
f4fcef65
TJ
43class PerThreadContainer
44{
45public:
84eef65a 46 typedef std::vector< ScopeTracker* > ScopeTrackerList;
f4fcef65
TJ
47
48 /// List of currently active scope trackers
49 ScopeTrackerList scope_tracker_list;
50
51 /// Precomputed indent levels
52 std::vector< std::string > indents;
53};
b6fb82a2
RP
54
55namespace
56{
57
f4fcef65
TJ
58/// Internal TLS (thread local storage) data container
59boost::thread_specific_ptr<PerThreadContainer> thread_container;
b6fb82a2 60
f4fcef65
TJ
61/**
62 * Helper function to retrieve TLS pointer.
63 * Initializes the pointer if called for the first time.
64 * @return Pointer to the per thread container
65 */
66static PerThreadContainer *TLS_get_container()
67{
68 // First call? Construct options container
69 if (thread_container.get() == NULL)
70 thread_container.reset(new PerThreadContainer());
b6fb82a2 71
f4fcef65 72 PerThreadContainer *per_thread = thread_container.get();
b6fb82a2 73
f4fcef65
TJ
74 return per_thread;
75}
b6fb82a2
RP
76
77/**
78 * @brief ensures indent level string to exist up to the desired level.
79 * @param level the desired indent level.
80 */
29bc7241 81static void ensure_indent_level(PerThreadContainer *per_thread, unsigned int level)
b6fb82a2 82{
f4fcef65
TJ
83 // First initialization?
84 if (per_thread->indents.empty())
85 {
86 per_thread->indents.reserve(10);
87 if (level < 10)
88 level = 10;
89
90 per_thread->indents.push_back("");
91 }
92
93 while (per_thread->indents.size() <= level)
b6fb82a2 94 {
f4fcef65 95 per_thread->indents.push_back( per_thread->indents.back() + " " );
b6fb82a2
RP
96 }
97} // eo ensure_indent_level(int)
98
b6fb82a2
RP
99} // eo namespace <anonymous>
100
101
102/*
103** implementation of ScopeTracker
104*/
105
106/**
107 * @brief constructor. initializes object with a source location and emits a ENTER message.
108 * @param loc the source location.
109 *
110 * the message is indented according to the current depth of nested ScopeTracker instances.
111 */
112ScopeTracker::ScopeTracker(
113 const SourceLocation& loc)
f4fcef65
TJ
114 : Location(loc)
115 , Depth(0)
116 , FuncDepth(0)
117 , PerThread(TLS_get_container())
b6fb82a2 118{
f4fcef65 119 if (!PerThread->scope_tracker_list.empty())
b6fb82a2 120 {
f4fcef65 121 ScopeTracker* last_tracker= PerThread->scope_tracker_list.back();
b6fb82a2
RP
122 if (Location)
123 {
124 if (last_tracker->Location
125 && last_tracker->Location.File == Location.File
126 && last_tracker->Location.FunctionName == Location.FunctionName)
127 {
128 FuncDepth= last_tracker->FuncDepth+1;
129 }
130 }
131 Depth= last_tracker->Depth + 1;
132 }
f4fcef65
TJ
133 ensure_indent_level(PerThread, Depth);
134 PerThread->scope_tracker_list.push_back(this);
b6fb82a2
RP
135 {
136 std::ostringstream ostr;
137 if (Location.FunctionName.empty())
138 {
139 ostr << "<unknown> (global scope?)";
140 }
141 else
142 {
143 ostr << Location.FunctionName;
144 if (FuncDepth>0)
145 {
146 ostr << "#" << FuncDepth+1;
147 }
148 }
149 Tag= ostr.str();
150 }
151 // spit a message
152 if (Logger::has_log_level(Logger::LogLevel::Debug))
153 {
f4fcef65 154 GlobalLogger.debug() << PerThread->indents[Depth] << "ENTER " << Tag;
b6fb82a2
RP
155 }
156} // eo ScopeTrcaker::ScopeTracker(const SourceLocation&)
157
158
159/**
160 * @brief destructor. emits a LEAVE message.
161 *
162 *
163 */
164ScopeTracker::~ScopeTracker()
165{
166 // spit a message
167 if (Logger::has_log_level(Logger::LogLevel::Debug))
168 {
f4fcef65 169 GlobalLogger.debug() << PerThread->indents[Depth] << "LEAVE " << Tag;
b6fb82a2 170 }
f4fcef65 171 if (PerThread->scope_tracker_list.empty())
b6fb82a2
RP
172 {
173 return;
174 }
f4fcef65 175 if (PerThread->scope_tracker_list.back() == this)
b6fb82a2 176 {
f4fcef65 177 PerThread->scope_tracker_list.pop_back();
b6fb82a2
RP
178 }
179 else
180 {
181 // oh hell, this should never be the case!
182 //TODO
183 GlobalLogger.error() << "inconsistency detected in scope tracker";
184 }
185} // eo ScopeTracker::~ScopeTracker()
186
187
188
189
190} // eo namespace Tracer
191} // eo namespace I2n