1
2//
3// This source file is part of appleseed.
4// Visit http://appleseedhq.net/ for additional information and resources.
5//
6// This software is released under the MIT license.
7//
8// Copyright (c) 2012-2013 Esteban Tovagliari, Jupiter Jazz Limited
9// Copyright (c) 2014-2017 Esteban Tovagliari, The appleseedhq Organization
10//
11// Permission is hereby granted, free of charge, to any person obtaining a copy
12// of this software and associated documentation files (the "Software"), to deal
13// in the Software without restriction, including without limitation the rights
14// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15// copies of the Software, and to permit persons to whom the Software is
16// furnished to do so, subject to the following conditions:
17//
18// The above copyright notice and this permission notice shall be included in
19// all copies or substantial portions of the Software.
20//
21// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27// THE SOFTWARE.
28//
29
30// appleseed.python headers.
31#include "pyseed.h" // has to be first, to avoid redefinition warnings
32#include "gillocks.h"
33
34// appleseed.renderer headers.
35#include "renderer/global/globallogger.h"
36
37// appleseed.foundation headers.
38#include "foundation/platform/compiler.h"
39#include "foundation/utility/log.h"
40
41// Standard headers.
42#include <cstddef>
43#include <cstdio>
44#include <string>
45
46namespace bpy = boost::python;
47using namespace foundation;
48using namespace renderer;
49
50struct ILogTargetWrap
51 : public ILogTarget
52 , public bpy::wrapper<ILogTarget>
53{
54 ILogTargetWrap() {}
55 ~ILogTargetWrap() {}
56
57 virtual void release() APPLESEED_OVERRIDE
58 {
59 delete this;
60 }
61
62 virtual void write(
63 const LogMessage::Category category,
64 const char* file,
65 const size_t line,
66 const char* header,
67 const char* message) APPLESEED_OVERRIDE
68 {
69 // Because this can be called from multiple threads
70 // we need to lock Python here.
71 ScopedGILLock lock;
72
73 try
74 {
75 this->get_override("write")(category, file, line, header, message);
76 }
77 catch (bpy::error_already_set)
78 {
79 PyErr_Print();
80 }
81 }
82};
83
84// Work around a regression in Visual Studio 2015 Update 3.
85#if defined(_MSC_VER) && _MSC_VER == 1900
86namespace boost
87{
88 template <> ILogTargetWrap const volatile* get_pointer<ILogTargetWrap const volatile>(ILogTargetWrap const volatile* p) { return p; }
89 template <> Logger const volatile* get_pointer<Logger const volatile>(Logger const volatile* p) { return p; }
90}
91#endif
92
93namespace
94{
95
96 Logger* get_global_logger()
97 {
98 return &global_logger();
99 }
100
101 void logger_set_all_formats(Logger* logger, const std::string& format)
102 {
103 logger->set_all_formats(format);
104 }
105
106 void logger_set_format(Logger* logger, const LogMessage::Category category, const std::string& format)
107 {
108 logger->set_format(category, format);
109 }
110
111 void logger_add_target(Logger* logger, bpy::object target)
112 {
113 ILogTargetWrap* p = bpy::extract<ILogTargetWrap*>(target);
114 assert(p);
115
116 logger->add_target(p);
117 }
118
119 void logger_remove_target(Logger* logger, bpy::object target)
120 {
121 ILogTargetWrap* p = bpy::extract<ILogTargetWrap*>(target);
122 assert(p);
123
124 logger->remove_target(p);
125 }
126}
127
128void bind_logger()
129{
130 bpy::class_<ILogTargetWrap, boost::shared_ptr<ILogTargetWrap>, boost::noncopyable>("ILogTarget")
131 .def("write", bpy::pure_virtual(&ILogTarget::write))
132 ;
133
134 bpy::enum_<LogMessage::Category>("LogMessageCategory")
135 .value("Info", LogMessage::Info)
136 .value("Debug", LogMessage::Debug)
137 .value("Warning", LogMessage::Warning)
138 .value("Error", LogMessage::Error)
139 .value("Fatal", LogMessage::Fatal)
140 ;
141
142 bpy::class_<Logger, boost::noncopyable>("Logger", bpy::no_init)
143 .def("set_enabled", &Logger::set_enabled)
144 .def("set_verbosity_level", &Logger::set_verbosity_level)
145 .def("get_verbosity_level", &Logger::get_verbosity_level)
146 .def("reset_all_formats", &Logger::reset_all_formats)
147 .def("reset_format", &Logger::reset_format)
148 .def("set_all_formats", logger_set_all_formats)
149 .def("set_format", logger_set_format)
150 .def("get_format", &Logger::get_format)
151 .def("add_target", logger_add_target)
152 .def("remove_target", logger_remove_target)
153 ;
154
155 bpy::def("global_logger", &get_global_logger, bpy::return_value_policy<bpy::reference_existing_object>());
156}
157