Log filter can be configured to write to a given file using 'filename'
[metaproxy-moved-to-github.git] / src / filter_log.cpp
1 /* $Id: filter_log.cpp,v 1.19 2006-06-19 13:08:00 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         };
46         // Only used during configure stage (no threading)
47         static std::list<LFilePtr> filter_log_files;
48     }
49 }
50
51 yf::Log::Rep::Rep()
52 {
53     m_req_apdu = true;
54     m_res_apdu = true;
55     m_req_session = true;
56     m_res_session = true;
57 }
58
59 yf::Log::Log(const std::string &x) : m_p(new Rep)
60 {
61     m_p->m_msg = x;
62 }
63
64 yf::Log::Log() : m_p(new Rep)
65 {
66 }
67
68 yf::Log::~Log() {}
69
70 void stream_write(ODR o, void *handle, int type, const char *buf, int len)
71 {
72     yf::Log::LFile *lfile = (yf::Log::LFile*) handle;
73     lfile->out.write(buf, len);
74 }
75
76 void yf::Log::process(mp::Package &package) const
77 {
78     Z_GDU *gdu;
79
80     // getting timestamp for receiving of package
81     boost::posix_time::ptime receive_time
82         = boost::posix_time::microsec_clock::local_time();
83
84     // scope for locking Ostream 
85     { 
86         boost::mutex::scoped_lock scoped_lock(m_p->m_file->m_mutex);
87         
88         if (m_p->m_req_session)
89         {
90             m_p->m_file->out << receive_time << " " << m_p->m_msg;
91             m_p->m_file->out << " request id=" << package.session().id();
92             m_p->m_file->out << " close=" 
93                              << (package.session().is_closed() ? "yes" : "no")
94                              << "\n";
95         }
96         if (m_p->m_req_apdu)
97         {
98             gdu = package.request().get();
99             if (gdu)
100             {
101                 mp::odr odr(ODR_PRINT);
102                 odr_set_stream(odr, m_p->m_file.get(), stream_write, 0);
103                 z_GDU(odr, &gdu, 0, 0);
104             }
105         }
106         m_p->m_file->out.flush();
107     }
108
109     // unlocked during move
110     package.move();
111
112     // getting timestamp for sending of package
113     boost::posix_time::ptime send_time
114         = boost::posix_time::microsec_clock::local_time();
115
116     boost::posix_time::time_duration duration = send_time - receive_time;
117
118     // scope for locking Ostream 
119     { 
120         boost::mutex::scoped_lock scoped_lock(m_p->m_file->m_mutex);
121         if (m_p->m_res_session)
122         {
123             m_p->m_file->out << send_time << " " << m_p->m_msg;
124             m_p->m_file->out << " response id=" << package.session().id();
125             m_p->m_file->out << " close=" 
126                              << (package.session().is_closed() ? "yes " : "no ")
127                              << "duration=" << duration      
128                              << "\n";
129         }
130         if (m_p->m_res_apdu)
131         {
132             gdu = package.response().get();
133             if (gdu)
134             {
135                 mp::odr odr(ODR_PRINT);
136                 odr_set_stream(odr, m_p->m_file.get(), stream_write, 0);
137                 z_GDU(odr, &gdu, 0, 0);
138             }
139         }
140         m_p->m_file->out.flush();
141     }
142 }
143
144 yf::Log::LFile::LFile(std::string fname) : m_fname(fname)
145 {
146     out.open(fname.c_str());
147 }
148
149 void yf::Log::Rep::openfile(const std::string &fname)
150 {
151     std::list<LFilePtr>::const_iterator it = filter_log_files.begin();
152     for (; it != filter_log_files.end(); it++)
153     {
154         if ((*it)->m_fname == fname)
155         {
156             m_file = *it;
157             return;
158         }
159     }
160     LFilePtr newfile(new LFile(fname));
161     filter_log_files.push_back(newfile);
162     m_file = newfile;
163 }
164
165 void yf::Log::configure(const xmlNode *ptr)
166 {
167     for (ptr = ptr->children; ptr; ptr = ptr->next)
168     {
169         if (ptr->type != XML_ELEMENT_NODE)
170             continue;
171         if (!strcmp((const char *) ptr->name, "message"))
172             m_p->m_msg = mp::xml::get_text(ptr);
173         else if (!strcmp((const char *) ptr->name, "filename"))
174         {
175             std::string fname = mp::xml::get_text(ptr);
176             m_p->openfile(fname);
177         }
178         else if (!strcmp((const char *) ptr->name, "category"))
179         {
180             const struct _xmlAttr *attr;
181             for (attr = ptr->properties; attr; attr = attr->next)
182             {
183                 if (!strcmp((const char *) attr->name, "request-apdu"))
184                     m_p->m_req_apdu = mp::xml::get_bool(attr->children, true);
185                 else if (!strcmp((const char *) attr->name, "response-apdu"))
186                     m_p->m_res_apdu = mp::xml::get_bool(attr->children, true);
187                 else if (!strcmp((const char *) attr->name,
188                                  "request-session"))
189                     m_p->m_req_session = 
190                         mp::xml::get_bool(attr->children, true);
191                 else if (!strcmp((const char *) attr->name, 
192                                  "response-session"))
193                     m_p->m_res_session = 
194                         mp::xml::get_bool(attr->children, true);
195                 else
196                     throw mp::filter::FilterException(
197                         "Bad attribute " + std::string((const char *)
198                                                        attr->name));
199             }
200         }
201         else
202         {
203             throw mp::filter::FilterException("Bad element " 
204                                                + std::string((const char *)
205                                                              ptr->name));
206         }
207     }
208     if (!m_p->m_file)
209         m_p->openfile("metaproxy.log");
210 }
211
212 static mp::filter::Base* filter_creator()
213 {
214     return new mp::filter::Log;
215 }
216
217 extern "C" {
218     struct metaproxy_1_filter_struct metaproxy_1_filter_log = {
219         0,
220         "log",
221         filter_creator
222     };
223 }
224
225 /*
226  * Local variables:
227  * c-basic-offset: 4
228  * indent-tabs-mode: nil
229  * c-file-style: "stroustrup"
230  * End:
231  * vim: shiftwidth=4 tabstop=8 expandtab
232  */