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 | |
46 | namespace bpy = boost::python; |
47 | using namespace foundation; |
48 | using namespace renderer; |
49 | |
50 | struct 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* , |
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 |
86 | namespace 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 | |
93 | namespace |
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 | |
128 | void 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 | |