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
25namespace Poco {
26namespace Data {
27
28
29using namespace Keywords;
30
31
32const std::string SQLChannel::PROP_CONNECTOR("connector");
33const std::string SQLChannel::PROP_CONNECT("connect");
34const std::string SQLChannel::PROP_NAME("name");
35const std::string SQLChannel::PROP_TABLE("table");
36const std::string SQLChannel::PROP_ARCHIVE_TABLE("archive");
37const std::string SQLChannel::PROP_MAX_AGE("keep");
38const std::string SQLChannel::PROP_ASYNC("async");
39const std::string SQLChannel::PROP_TIMEOUT("timeout");
40const std::string SQLChannel::PROP_THROW("throw");
41
42
43SQLChannel::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
56SQLChannel::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
74SQLChannel::~SQLChannel()
75{
76 try
77 {
78 close();
79 }
80 catch (...)
81 {
82 poco_unexpected();
83 }
84}
85
86
87void 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
97void SQLChannel::close()
98{
99 wait();
100}
101
102
103void SQLChannel::log(const Message& msg)
104{
105 if (_async) logAsync(msg);
106 else logSync(msg);
107}
108
109
110void 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
125void 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
149void 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
226std::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
269void 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
289void SQLChannel::registerChannel()
290{
291 Poco::LoggingFactory::defaultFactory().registerChannelClass("SQLChannel",
292 new Poco::Instantiator<SQLChannel, Poco::Channel>);
293}
294
295
296} } // namespace Poco::Data
297