Commit | Line | Data |
---|---|---|
0e23f538 TJ |
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 | */ | |
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 | |
36 | namespace I2n | |
37 | { | |
38 | namespace Tracer | |
39 | { | |
40 | ||
41 | using Logger::GlobalLogger; | |
42 | ||
f4fcef65 TJ |
43 | class PerThreadContainer |
44 | { | |
45 | public: | |
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 | |
55 | namespace | |
56 | { | |
57 | ||
f4fcef65 TJ |
58 | /// Internal TLS (thread local storage) data container |
59 | boost::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 | */ | |
66 | static 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 | 81 | static 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 | */ | |
112 | ScopeTracker::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 | */ | |
164 | ScopeTracker::~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 |