1 | // |
2 | // SQLChannel.cpp |
3 | // |
4 | // Library: Data |
5 | // Package: Logging |
6 | // Module: SQLChannel |
7 | // |
8 | // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Data/SQLChannel.h" |
16 | #include "Poco/Data/SessionFactory.h" |
17 | #include "Poco/DateTime.h" |
18 | #include "Poco/LoggingFactory.h" |
19 | #include "Poco/Instantiator.h" |
20 | #include "Poco/NumberParser.h" |
21 | #include "Poco/NumberFormatter.h" |
22 | #include "Poco/Format.h" |
23 | |
24 | |
25 | namespace Poco { |
26 | namespace Data { |
27 | |
28 | |
29 | using namespace Keywords; |
30 | |
31 | |
32 | const std::string SQLChannel::PROP_CONNECTOR("connector" ); |
33 | const std::string SQLChannel::PROP_CONNECT("connect" ); |
34 | const std::string SQLChannel::PROP_NAME("name" ); |
35 | const std::string SQLChannel::PROP_TABLE("table" ); |
36 | const std::string SQLChannel::PROP_ARCHIVE_TABLE("archive" ); |
37 | const std::string SQLChannel::PROP_MAX_AGE("keep" ); |
38 | const std::string SQLChannel::PROP_ASYNC("async" ); |
39 | const std::string SQLChannel::PROP_TIMEOUT("timeout" ); |
40 | const std::string SQLChannel::PROP_THROW("throw" ); |
41 | |
42 | |
43 | SQLChannel::SQLChannel(): |
44 | _name("-" ), |
45 | _table("T_POCO_LOG" ), |
46 | _timeout(1000), |
47 | _throw(true), |
48 | _async(true), |
49 | _pid(), |
50 | _tid(), |
51 | _priority() |
52 | { |
53 | } |
54 | |
55 | |
56 | SQLChannel::SQLChannel(const std::string& connector, |
57 | const std::string& connect, |
58 | const std::string& name): |
59 | _connector(connector), |
60 | _connect(connect), |
61 | _name(name), |
62 | _table("T_POCO_LOG" ), |
63 | _timeout(1000), |
64 | _throw(true), |
65 | _async(true), |
66 | _pid(), |
67 | _tid(), |
68 | _priority() |
69 | { |
70 | open(); |
71 | } |
72 | |
73 | |
74 | SQLChannel::~SQLChannel() |
75 | { |
76 | try |
77 | { |
78 | close(); |
79 | } |
80 | catch (...) |
81 | { |
82 | poco_unexpected(); |
83 | } |
84 | } |
85 | |
86 | |
87 | void SQLChannel::open() |
88 | { |
89 | if (_connector.empty() || _connect.empty()) |
90 | throw IllegalStateException("Connector and connect string must be non-empty." ); |
91 | |
92 | _pSession = new Session(_connector, _connect); |
93 | initLogStatement(); |
94 | } |
95 | |
96 | |
97 | void SQLChannel::close() |
98 | { |
99 | wait(); |
100 | } |
101 | |
102 | |
103 | void SQLChannel::log(const Message& msg) |
104 | { |
105 | if (_async) logAsync(msg); |
106 | else logSync(msg); |
107 | } |
108 | |
109 | |
110 | void SQLChannel::logAsync(const Message& msg) |
111 | { |
112 | poco_check_ptr (_pLogStatement); |
113 | if (0 == wait() && !_pLogStatement->done() && !_pLogStatement->initialized()) |
114 | { |
115 | if (_throw) |
116 | throw TimeoutException("Timed out waiting for previous statement completion" ); |
117 | else return; |
118 | } |
119 | |
120 | if (!_pSession || !_pSession->isConnected()) open(); |
121 | logSync(msg); |
122 | } |
123 | |
124 | |
125 | void SQLChannel::logSync(const Message& msg) |
126 | { |
127 | if (_pArchiveStrategy) _pArchiveStrategy->archive(); |
128 | |
129 | _source = msg.getSource(); |
130 | _pid = msg.getPid(); |
131 | _thread = msg.getThread(); |
132 | _tid = msg.getTid(); |
133 | _priority = msg.getPriority(); |
134 | _text = msg.getText(); |
135 | _dateTime = msg.getTime(); |
136 | if (_source.empty()) _source = _name; |
137 | |
138 | try |
139 | { |
140 | _pLogStatement->execute(); |
141 | } |
142 | catch (Exception&) |
143 | { |
144 | if (_throw) throw; |
145 | } |
146 | } |
147 | |
148 | |
149 | void SQLChannel::setProperty(const std::string& name, const std::string& value) |
150 | { |
151 | if (name == PROP_NAME) |
152 | { |
153 | _name = value; |
154 | if (_name.empty()) _name = "-" ; |
155 | } |
156 | else if (name == PROP_CONNECTOR) |
157 | { |
158 | _connector = value; |
159 | close(); open(); |
160 | } |
161 | else if (name == PROP_CONNECT) |
162 | { |
163 | _connect = value; |
164 | close(); open(); |
165 | } |
166 | else if (name == PROP_TABLE) |
167 | { |
168 | _table = value; |
169 | initLogStatement(); |
170 | } |
171 | else if (name == PROP_ARCHIVE_TABLE) |
172 | { |
173 | if (value.empty()) |
174 | { |
175 | _pArchiveStrategy = 0; |
176 | } |
177 | else if (_pArchiveStrategy) |
178 | { |
179 | _pArchiveStrategy->setDestination(value); |
180 | } |
181 | else |
182 | { |
183 | _pArchiveStrategy = new ArchiveByAgeStrategy(_connector, _connect, _table, value); |
184 | } |
185 | } |
186 | else if (name == PROP_MAX_AGE) |
187 | { |
188 | if (value.empty() || "forever" == value) |
189 | { |
190 | _pArchiveStrategy = 0; |
191 | } |
192 | else if (_pArchiveStrategy) |
193 | { |
194 | _pArchiveStrategy->setThreshold(value); |
195 | } |
196 | else |
197 | { |
198 | ArchiveByAgeStrategy* p = new ArchiveByAgeStrategy(_connector, _connect, _table); |
199 | p->setThreshold(value); |
200 | _pArchiveStrategy = p; |
201 | } |
202 | } |
203 | else if (name == PROP_ASYNC) |
204 | { |
205 | _async = isTrue(value); |
206 | initLogStatement(); |
207 | } |
208 | else if (name == PROP_TIMEOUT) |
209 | { |
210 | if (value.empty() || '0' == value[0]) |
211 | _timeout = Statement::WAIT_FOREVER; |
212 | else |
213 | _timeout = NumberParser::parse(value); |
214 | } |
215 | else if (name == PROP_THROW) |
216 | { |
217 | _throw = isTrue(value); |
218 | } |
219 | else |
220 | { |
221 | Channel::setProperty(name, value); |
222 | } |
223 | } |
224 | |
225 | |
226 | std::string SQLChannel::getProperty(const std::string& name) const |
227 | { |
228 | if (name == PROP_NAME) |
229 | { |
230 | if (_name != "-" ) return _name; |
231 | else return "" ; |
232 | } |
233 | else if (name == PROP_CONNECTOR) |
234 | { |
235 | return _connector; |
236 | } |
237 | else if (name == PROP_CONNECT) |
238 | { |
239 | return _connect; |
240 | } |
241 | else if (name == PROP_TABLE) |
242 | { |
243 | return _table; |
244 | } |
245 | else if (name == PROP_ARCHIVE_TABLE) |
246 | { |
247 | return _pArchiveStrategy ? _pArchiveStrategy->getDestination() : "" ; |
248 | } |
249 | else if (name == PROP_MAX_AGE) |
250 | { |
251 | return _pArchiveStrategy ? _pArchiveStrategy->getThreshold() : "forever" ; |
252 | } |
253 | else if (name == PROP_TIMEOUT) |
254 | { |
255 | return NumberFormatter::format(_timeout); |
256 | } |
257 | else if (name == PROP_THROW) |
258 | { |
259 | if (_throw) return "true" ; |
260 | else return "false" ; |
261 | } |
262 | else |
263 | { |
264 | return Channel::getProperty(name); |
265 | } |
266 | } |
267 | |
268 | |
269 | void SQLChannel::initLogStatement() |
270 | { |
271 | _pLogStatement = new Statement(*_pSession); |
272 | |
273 | std::string sql; |
274 | Poco::format(sql, "INSERT INTO %s VALUES (?,?,?,?,?,?,?,?)" , _table); |
275 | *_pLogStatement << sql, |
276 | use(_source), |
277 | use(_name), |
278 | use(_pid), |
279 | use(_thread), |
280 | use(_tid), |
281 | use(_priority), |
282 | use(_text), |
283 | use(_dateTime); |
284 | |
285 | if (_async) _pLogStatement->setAsync(); |
286 | } |
287 | |
288 | |
289 | void SQLChannel::registerChannel() |
290 | { |
291 | Poco::LoggingFactory::defaultFactory().registerChannelClass("SQLChannel" , |
292 | new Poco::Instantiator<SQLChannel, Poco::Channel>); |
293 | } |
294 | |
295 | |
296 | } } // namespace Poco::Data |
297 | |