2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
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.
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.
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.
21 * @brief implementation of tracing functionality.
23 * @copyright © Copyright 2008,2011 by Intra2net AG
25 * Every thread gets its' own ScopeTracker stack via TLS (thread local storage)
29 #include "tracefunc.hpp"
34 #include <boost/thread/tss.hpp>
36 #include <stringfunc.hxx>
43 using Logger::GlobalLogger;
45 class PerThreadContainer
48 typedef std::vector< ScopeTracker* > ScopeTrackerList;
50 /// List of currently active scope trackers
51 ScopeTrackerList scope_tracker_list;
53 /// Precomputed indent levels
54 std::vector< std::string > indents;
60 /// Internal TLS (thread local storage) data container
61 boost::thread_specific_ptr<PerThreadContainer> thread_container;
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 or NULL if error occurs
68 static PerThreadContainer *TLS_get_container() throw ()
70 // First call? Construct options container
71 if (thread_container.get() == NULL)
75 thread_container.reset(new PerThreadContainer());
83 PerThreadContainer *per_thread = thread_container.get();
89 * @brief ensures indent level string to exist up to the desired level.
90 * @param level the desired indent level.
92 static void ensure_indent_level(PerThreadContainer *per_thread, unsigned int level)
93 throw(std::length_error, std::bad_alloc)
95 // First initialization?
96 if (per_thread->indents.empty())
98 per_thread->indents.reserve(10);
102 per_thread->indents.push_back("");
105 while (per_thread->indents.size() <= level)
107 per_thread->indents.push_back( per_thread->indents.back() + " " );
109 } // eo ensure_indent_level(int)
112 * @brief try logging that some problem occurred
114 * Keep in mind that problem could be with the logger itself, so wrap all this
115 * in a try-catch agin
117 static void try_logging_error(const std::string &message) throw ()
121 GlobalLogger.debug() << "Problem occurred in ScopeTracker: " << message;
124 { // nothing more we can do
129 } // eo namespace <anonymous>
133 ** implementation of ScopeTracker
137 * @brief constructor. initializes object with a source location and emits a ENTER message.
138 * @param loc the source location.
140 * the message is indented according to the current depth of nested ScopeTracker instances.
142 * All exceptions happening in here (from vector::reserve, vector::push_back, acquiring lock for logger)
143 * are caught. Will try to log only that problem occurred
145 ScopeTracker::ScopeTracker(
146 const SourceLocation& loc) throw ()
150 , PerThread(TLS_get_container())
152 if (PerThread == NULL)
154 try_logging_error("Failed to get thread local storage");
160 if (!PerThread->scope_tracker_list.empty())
162 ScopeTracker* last_tracker= PerThread->scope_tracker_list.back();
165 if (last_tracker->Location
166 && last_tracker->Location.File == Location.File
167 && last_tracker->Location.FunctionName == Location.FunctionName)
169 FuncDepth= last_tracker->FuncDepth+1;
172 Depth= last_tracker->Depth + 1;
175 ensure_indent_level(PerThread, Depth);
176 PerThread->scope_tracker_list.push_back(this);
179 if (Logger::has_log_level(Logger::LogLevel::Debug))
181 GlobalLogger.debug() << PerThread->indents[Depth] << "ENTER " << get_tag();
186 try_logging_error("Caught exception in constructor");
188 } // eo ScopeTracker::ScopeTracker(const SourceLocation&)
192 * @brief create Tag if empty; return reference to it
194 * Moved this from constructor into own function to avoid creating Tag if it is
195 * not required (i.e. log level is not DEBUG) but still create it only once and
196 * ensure it is available if log level changes inside tracked function
198 std::string& ScopeTracker::get_tag()
202 if (Location.FunctionName.empty())
204 Tag = "<unknown> (global scope?)";
208 std::ostringstream ostr;
209 ostr << shorten_stl_types(Location.FunctionName);
212 ostr << "#" << FuncDepth+1;
222 * @brief destructor. emits a LEAVE message.
224 * All exceptions are caught, will try to log only that some problem occurred
226 ScopeTracker::~ScopeTracker() throw ()
228 if (PerThread == NULL)
230 try_logging_error("Failed to get thread local storage");
237 if (Logger::has_log_level(Logger::LogLevel::Debug))
239 GlobalLogger.debug() << PerThread->indents[Depth] << "LEAVE " << get_tag();
241 if (PerThread->scope_tracker_list.empty())
245 if (PerThread->scope_tracker_list.back() == this)
247 PerThread->scope_tracker_list.pop_back();
251 // oh hell, this should never be the case!
253 GlobalLogger.error() << "inconsistency detected in scope tracker";
258 try_logging_error("Caught exception in destructor");
260 } // eo ScopeTracker::~ScopeTracker()
265 } // eo namespace Tracer
266 } // eo namespace I2n