]> git.sesse.net Git - casparcg/commitdiff
Created a context_info attachment to our exceptions with information about the contex...
authorHelge Norberg <helge.norberg@svt.se>
Wed, 2 Dec 2015 16:25:46 +0000 (17:25 +0100)
committerHelge Norberg <helge.norberg@svt.se>
Wed, 2 Dec 2015 16:25:46 +0000 (17:25 +0100)
common/CMakeLists.txt
common/except.cpp [new file with mode: 0644]
common/except.h

index a4bc89b88dc0f5501da29bfbff57399e779aef38..d39d10a7df043bd2a106222e95fcb331aedbeb57 100644 (file)
@@ -8,6 +8,7 @@ set(SOURCES
 
                base64.cpp
                env.cpp
+               except.cpp
                filesystem.cpp
                log.cpp
                polling_filesystem_monitor.cpp
diff --git a/common/except.cpp b/common/except.cpp
new file mode 100644 (file)
index 0000000..7257e79
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "stdafx.h"
+
+#include "except.h"
+
+#include <boost/thread/tss.hpp>
+#include <boost/algorithm/string/join.hpp>
+
+namespace {
+
+boost::thread_specific_ptr<std::list<std::string>>& context_stacks_per_thread()
+{
+       static boost::thread_specific_ptr<std::list<std::string>> instances;
+
+       return instances;
+}
+
+}
+
+namespace caspar {
+
+std::list<std::string>& context_stack_for_thread()
+{
+       auto local = context_stacks_per_thread().get();
+
+       if (!local)
+       {
+               local = new std::list<std::string>();
+               context_stacks_per_thread().reset(local);
+       }
+
+       return *local;
+}
+
+std::string get_context()
+{
+       return boost::join(context_stack_for_thread(), "");
+}
+
+scoped_context::scoped_context()
+       : scoped_context::scoped_context("")
+{
+}
+
+scoped_context::scoped_context(std::string msg)
+       : for_thread_(context_stack_for_thread())
+{
+       for_thread_.push_back(std::move(msg));
+       msg_ = &for_thread_.back();
+}
+
+void scoped_context::replace_msg(std::string msg)
+{
+       if (&for_thread_ != &context_stack_for_thread())
+               CASPAR_THROW_EXCEPTION(invalid_operation() << msg_info("Called from wrong thread"));
+
+       *msg_ = std::move(msg);
+}
+
+void scoped_context::clear_msg()
+{
+       replace_msg("");
+}
+
+scoped_context::~scoped_context()
+{
+       for_thread_.pop_back();
+}
+
+
+
+std::string get_message_and_context(const caspar_exception& e)
+{
+       std::string result;
+
+       auto msg = boost::get_error_info<msg_info_t>(e);
+       auto ctx = boost::get_error_info<context_info_t>(e);
+
+       if (msg)
+               result += *msg;
+
+       if (ctx && !ctx->empty())
+       {
+               result += " (";
+               result += *ctx;
+               result += ")";
+       }
+
+       if (!result.empty() && result.back() != '.')
+               result += ".";
+
+       return result;
+}
+
+}
index 5a498acbeaa7cdc910c6839b2b4d9281ca6f7b30..6a52f3530a237b79bc5539e66c2220a125785392 100644 (file)
 #include "os/stack_trace.h"
 
 #include <exception>
+#include <list>
+
 #include <boost/exception/all.hpp>
 #include <boost/exception/error_info.hpp>
 #include <boost/throw_exception.hpp>
+#include <boost/noncopyable.hpp>
 
 namespace caspar {
 
@@ -39,6 +42,7 @@ typedef boost::error_info<struct tag_call_stack_info, std::string>    call_stack_in
 typedef boost::error_info<struct tag_error_info,               std::string>    error_info_t;
 typedef boost::error_info<struct tag_source_info,              std::string>    source_info_t;
 typedef boost::error_info<struct tag_file_name_info,   std::string>    file_name_info_t;
+typedef boost::error_info<struct tag_context_info,             std::string>    context_info_t;
 
 template<typename T>
 inline arg_name_info_t         arg_name_info(const T& str)             {return arg_name_info_t(u8(str));}
@@ -54,6 +58,8 @@ template<typename T>
 inline source_info_t           source_info(const T& str)               {return source_info_t(u8(str));}
 template<typename T>
 inline file_name_info_t                file_name_info(const T& str)    {return file_name_info_t(u8(str));}
+template<typename T>
+inline context_info_t          context_info(const T& str)              {return context_info_t(u8(str));}
 
 typedef boost::error_info<struct tag_line_info, size_t>                                                line_info;
 typedef boost::error_info<struct tag_nested_exception_, std::exception_ptr> nested_exception;
@@ -88,7 +94,39 @@ struct not_implemented                       : virtual caspar_exception {};
 struct user_error                              : virtual caspar_exception {};
 struct not_supported                   : virtual user_error {};
 
-#define CASPAR_THROW_EXCEPTION(e) BOOST_THROW_EXCEPTION(e << call_stack_info(caspar::get_call_stack()))
+std::string get_context();
+
+class scoped_context : boost::noncopyable
+{
+public:
+       scoped_context();
+       scoped_context(std::string msg);
+       template <typename Str>
+       scoped_context(Str msg)
+               : scoped_context(u8(std::move(msg)))
+       {
+       }
+
+       ~scoped_context();
+       void replace_msg(std::string msg);
+       template <typename Str>
+       void replace_msg(std::string msg)
+       {
+               replace_msg(u8(std::move(msg)));
+       }
+       void clear_msg();
+private:
+       std::list<std::string>& for_thread_;
+       std::string*                    msg_;
+};
+
+#define _CASPAR_GENERATE_UNIQUE_IDENTIFIER_CAT(name, line) name##line
+#define _CASPAR_GENERATE_UNIQUE_IDENTIFIER(name, line) _CASPAR_GENERATE_UNIQUE_IDENTIFIER_CAT(name, line)
+#define CASPAR_SCOPED_CONTEXT_MSG(ctx_msg) ::caspar::scoped_context _CASPAR_GENERATE_UNIQUE_IDENTIFIER(SCOPED_CONTEXT, __LINE__)(u8(ctx_msg));
+
+#define CASPAR_THROW_EXCEPTION(e) BOOST_THROW_EXCEPTION(e << call_stack_info(caspar::get_call_stack()) << context_info(get_context()))
+
+std::string get_message_and_context(const caspar_exception& e);
 
 }