removed superflous comment
[metaproxy-moved-to-github.git] / src / filter_log.cpp
1 /* $Id: filter_log.cpp,v 1.26 2006-08-31 12:56:40 marc Exp $
2    Copyright (c) 2005-2006, Index Data.
3
4    See the LICENSE file for details
5  */
6
7 #include "filter_log.hpp"
8 #include "config.hpp"
9 #include "package.hpp"
10
11 #include <string>
12 #include <sstream>
13 #include <boost/thread/mutex.hpp>
14 #include <boost/date_time/posix_time/posix_time.hpp>
15
16 #include "gduutil.hpp"
17 #include "util.hpp"
18 #include "xmlutil.hpp"
19
20 #include <fstream>
21 #include <yaz/zgdu.h>
22 #include <yaz/wrbuf.h>
23 #include <yaz/querytowrbuf.h>
24
25
26 namespace mp = metaproxy_1;
27 namespace yf = metaproxy_1::filter;
28
29 namespace metaproxy_1 {
30     namespace filter {
31         class Log::LFile {
32         public:
33             boost::mutex m_mutex;
34             std::string m_fname;
35             std::ofstream fout;
36             std::ostream &out;
37             LFile(std::string fname);
38             LFile(std::string fname, std::ostream &use_this);
39         };
40         typedef boost::shared_ptr<Log::LFile> LFilePtr;
41         class Log::Rep {
42             friend class Log;
43             Rep();
44             void openfile(const std::string &fname);
45             std::string m_msg_config;
46             LFilePtr m_file;
47             bool m_access;
48             bool m_req_apdu;
49             bool m_res_apdu;
50             bool m_req_session;
51             bool m_res_session;
52             bool m_init_options;
53         };
54         // Only used during configure stage (no threading)
55         static std::list<LFilePtr> filter_log_files;
56     }
57 }
58
59 yf::Log::Rep::Rep()
60 {
61     m_access = true;
62     m_req_apdu = false;
63     m_res_apdu = false;
64     m_req_session = false;
65     m_res_session = false;
66     m_init_options = false;
67     openfile("");
68 }
69
70 yf::Log::Log(const std::string &x) : m_p(new Rep)
71 {
72     m_p->m_msg_config = x;
73 }
74
75 yf::Log::Log() : m_p(new Rep)
76 {
77 }
78
79 yf::Log::~Log() {}
80
81 void stream_write(ODR o, void *handle, int type, const char *buf, int len)
82 {
83     yf::Log::LFile *lfile = (yf::Log::LFile*) handle;
84     lfile->out.write(buf, len);
85 }
86
87 void option_write(const char *name, void *handle)
88 {
89     yf::Log::LFile *lfile = (yf::Log::LFile*) handle;
90     lfile->out << " " << name;
91 }
92
93 void yf::Log::process(mp::Package &package) const
94 {
95     Z_GDU *gdu;
96
97     // getting timestamp for receiving of package
98     boost::posix_time::ptime receive_time
99         = boost::posix_time::microsec_clock::local_time();
100
101
102
103     // scope for locking Ostream 
104     { 
105         boost::mutex::scoped_lock scoped_lock(m_p->m_file->m_mutex);
106         
107  
108         if (m_p->m_access)
109         {
110             gdu = package.request().get();
111             if (gdu)          
112             {
113                 m_p->m_file->out
114                     //<< receive_time << " "
115                     //<< to_iso_string(receive_time) << " "
116                     << to_iso_extended_string(receive_time) << " "
117                     << m_p->m_msg_config << " "
118                     << package << " "
119                     << "000000.000000" << " " 
120                     << *gdu
121                     << "\n";
122             }
123         }
124
125         if (m_p->m_req_session)
126         {
127             m_p->m_file->out << receive_time << " " << m_p->m_msg_config;
128             m_p->m_file->out << " request id=" << package.session().id();
129             m_p->m_file->out << " close=" 
130                              << (package.session().is_closed() ? "yes" : "no")
131                              << "\n";
132         }
133
134         if (m_p->m_init_options)
135         {
136             gdu = package.request().get();
137             if (gdu && gdu->which == Z_GDU_Z3950 &&
138                 gdu->u.z3950->which == Z_APDU_initRequest)
139             {
140                 m_p->m_file->out << receive_time << " " << m_p->m_msg_config;
141                 m_p->m_file->out << " init options:";
142                 yaz_init_opt_decode(gdu->u.z3950->u.initRequest->options,
143                                     option_write, m_p->m_file.get());
144                 m_p->m_file->out << "\n";
145             }
146         }
147         
148         if (m_p->m_req_apdu)
149         {
150             gdu = package.request().get();
151             if (gdu)
152             {
153                 mp::odr odr(ODR_PRINT);
154                 odr_set_stream(odr, m_p->m_file.get(), stream_write, 0);
155                 z_GDU(odr, &gdu, 0, 0);
156             }
157         }
158         m_p->m_file->out.flush();
159     }
160     
161     // unlocked during move
162     package.move();
163
164     // getting timestamp for sending of package
165     boost::posix_time::ptime send_time
166         = boost::posix_time::microsec_clock::local_time();
167
168     boost::posix_time::time_duration duration = send_time - receive_time;
169
170     // scope for locking Ostream 
171     { 
172         boost::mutex::scoped_lock scoped_lock(m_p->m_file->m_mutex);
173
174         if (m_p->m_access)
175         {
176             gdu = package.response().get();
177             if (gdu)
178             {
179                 m_p->m_file->out
180                     //<< send_time << " "
181                     //<< to_iso_string(send_time) << " "
182                     << to_iso_extended_string(send_time) << " "
183                     << m_p->m_msg_config << " "
184                     << package << " "
185                     << to_iso_string(duration) << " "
186                     << *gdu
187                     << "\n";
188             }   
189         }
190
191         if (m_p->m_res_session)
192         {
193             m_p->m_file->out << send_time << " " << m_p->m_msg_config;
194             m_p->m_file->out << " response id=" << package.session().id();
195             m_p->m_file->out << " close=" 
196                              << (package.session().is_closed() ? "yes " : "no ")
197                              << "duration=" << duration      
198                              << "\n";
199         }
200
201         if (m_p->m_init_options)
202         {
203             gdu = package.response().get();
204             if (gdu && gdu->which == Z_GDU_Z3950 &&
205                 gdu->u.z3950->which == Z_APDU_initResponse)
206             {
207                 m_p->m_file->out << receive_time << " " << m_p->m_msg_config;
208                 m_p->m_file->out << " init options:";
209                 yaz_init_opt_decode(gdu->u.z3950->u.initResponse->options,
210                                     option_write, m_p->m_file.get());
211                 m_p->m_file->out << "\n";
212             }
213         }
214         
215         if (m_p->m_res_apdu)
216         {
217             gdu = package.response().get();
218             if (gdu)
219             {
220                 mp::odr odr(ODR_PRINT);
221                 odr_set_stream(odr, m_p->m_file.get(), stream_write, 0);
222                 z_GDU(odr, &gdu, 0, 0);
223             }
224         }
225         
226         m_p->m_file->out.flush();
227     }
228 }
229
230 yf::Log::LFile::LFile(std::string fname) : 
231     m_fname(fname), fout(fname.c_str()), out(fout)
232 {
233 }
234
235 yf::Log::LFile::LFile(std::string fname, std::ostream &use_this) : 
236     m_fname(fname), out(use_this)
237 {
238 }
239
240 void yf::Log::Rep::openfile(const std::string &fname)
241 {
242     std::list<LFilePtr>::const_iterator it = filter_log_files.begin();
243     for (; it != filter_log_files.end(); it++)
244     {
245         if ((*it)->m_fname == fname)
246         {
247             m_file = *it;
248             return;
249         }
250     }
251     // open stdout for empty file
252     LFilePtr newfile(fname.length() == 0 
253                      ? new LFile(fname, std::cout) 
254                      : new LFile(fname));
255     filter_log_files.push_back(newfile);
256     m_file = newfile;
257 }
258
259 void yf::Log::configure(const xmlNode *ptr)
260 {
261     for (ptr = ptr->children; ptr; ptr = ptr->next)
262     {
263         if (ptr->type != XML_ELEMENT_NODE)
264             continue;
265         if (!strcmp((const char *) ptr->name, "message"))
266             m_p->m_msg_config = mp::xml::get_text(ptr);
267         else if (!strcmp((const char *) ptr->name, "filename"))
268         {
269             std::string fname = mp::xml::get_text(ptr);
270             m_p->openfile(fname);
271         }
272         else if (!strcmp((const char *) ptr->name, "category"))
273         {
274             const struct _xmlAttr *attr;
275             for (attr = ptr->properties; attr; attr = attr->next)
276             {
277                 if (!strcmp((const char *) attr->name, 
278                                  "access"))
279                     m_p->m_access = 
280                         mp::xml::get_bool(attr->children, true);
281                 else if (!strcmp((const char *) attr->name, "request-apdu"))
282                     m_p->m_req_apdu = mp::xml::get_bool(attr->children, true);
283                 else if (!strcmp((const char *) attr->name, "response-apdu"))
284                     m_p->m_res_apdu = mp::xml::get_bool(attr->children, true);
285                 else if (!strcmp((const char *) attr->name, "apdu"))
286                 {
287                     m_p->m_req_apdu = mp::xml::get_bool(attr->children, true);
288                     m_p->m_res_apdu = m_p->m_req_apdu;
289                 }
290                 else if (!strcmp((const char *) attr->name,
291                                  "request-session"))
292                     m_p->m_req_session = 
293                         mp::xml::get_bool(attr->children, true);
294                 else if (!strcmp((const char *) attr->name, 
295                                  "response-session"))
296                     m_p->m_res_session = 
297                         mp::xml::get_bool(attr->children, true);
298                 else if (!strcmp((const char *) attr->name,
299                                  "session"))
300                 {
301                     m_p->m_req_session = 
302                         mp::xml::get_bool(attr->children, true);
303                     m_p->m_res_session = m_p->m_req_session;
304                 }
305                 else if (!strcmp((const char *) attr->name, 
306                                  "init-options"))
307                     m_p->m_init_options = 
308                         mp::xml::get_bool(attr->children, true);
309                 else
310                     throw mp::filter::FilterException(
311                         "Bad attribute " + std::string((const char *)
312                                                        attr->name));
313             }
314         }
315         else
316         {
317             throw mp::filter::FilterException("Bad element " 
318                                                + std::string((const char *)
319                                                              ptr->name));
320         }
321     }
322 }
323
324 static mp::filter::Base* filter_creator()
325 {
326     return new mp::filter::Log;
327 }
328
329 extern "C" {
330     struct metaproxy_1_filter_struct metaproxy_1_filter_log = {
331         0,
332         "log",
333         filter_creator
334     };
335 }
336
337 /*
338  * Local variables:
339  * c-basic-offset: 4
340  * indent-tabs-mode: nil
341  * c-file-style: "stroustrup"
342  * End:
343  * vim: shiftwidth=4 tabstop=8 expandtab
344  */