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