TFCweb  1.0.4 $Rev: 483 $
TFC Primavera 2012: Nucli d'un servidor web
Log.cc
Veure la documentació d'aquest fitxer.
1 
8 /*
9  * Copyright (c) 2012 Toni Corvera
10  *
11  * This file is part of TFCWeb.
12  *
13  * TFCWeb is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * TFCWeb is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with TFCWeb. If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 #include "Log.h"
28 #include "utils.h"
29 
30 #include <algorithm>
31 #include <functional>
32 #include <iostream>
33 #include <boost/lexical_cast.hpp>
34 
35 using namespace std;
36 using boost::lexical_cast;
37 namespace fs = boost::filesystem;
38 
39 namespace tfc {
40 
42 //
43 // Missatges de logging
44 //
46 
48  return MissatgeLog();
49 }
50 
52 //
53 // Destins de logging
54 //
56 
57 
58 // Definició completa de la classe base
65 class DestiLogging {
66 public:
68  : nivell_(nivell)
69  {
70  // buit
71  }
72  virtual ~DestiLogging() {}
73  virtual ostream& os() = 0;
74  virtual NivellLog nivell() const {
75  return nivell_;
76  }
77  virtual void nivell(NivellLog nivell) {
78  nivell_ = nivell;
79  }
80  // TODO: Aquesta implementació (en base a les classes derivades) no m'agrada, però
81  // com que només es tracta de classes d'implementació la considero acceptable
82  virtual bool coincideix(const fs::path &) const {
83  return false;
84  }
85  virtual bool coincideix(const ostream &) const {
86  return false;
87  }
88 private:
90 };
91 
92 } // ns tfc
93 
94 namespace {
95 
96 using namespace tfc;
97 
101  void operator()(shared_ptr<DestiLogging> & dl) {
102  dl->nivell(nivell);
103  }
105 };
106 
108 template<typename TImpl>
110  const TImpl & i_;
111  bool operator()(const shared_ptr<DestiLogging> & dl) const {
112  return dl->coincideix(i_);
113  }
114  FunctorCoincideix(const TImpl & i) : i_(i) {}
115 };
116 
121 public:
123  : tfc::DestiLogging(nivell), ruta_(f), of_()
124  {
125  using namespace tfc;
126  // TODO: writeable!
127  assert( !fs::exists(f) || fs::is_regular_file(f) );
128  if (fs::exists(f) && !fs::is_regular_file(f)) {
129  throw ErrorLogNoValid("El fitxer de log "+f.string()+" no es pot escriure");
130  }
131  of_.open(f.string().c_str(), ios_base::out|ios_base::app);
132  if (!of_.good()) {
133  throw ErrorLogNoValid("Error en obrir el fitxer de log "+f.string());
134  }
135  }
136 
137  virtual ~DestiFitxer() {
138  of_.close();
139  }
140 
141  virtual ostream& os() {
142  return of_;
143  }
144  virtual bool coincideix(const fs::path & f) const {
145  return ( f == ruta_ );
146  }
147 private:
149  ofstream of_;
150 };
151 
156 public:
158  : tfc::DestiLogging(nivell), os_(o)
159  {
160  // buit
161  }
162  virtual ~DestiOstream() {}
163  virtual ostream& os() {
164  return os_;
165  }
166  virtual bool coincideix(const ostream & os) const {
167  return ( &os == &os_ );
168  }
169 private:
170  ostream & os_;
171 };
172 
173 } // ns anònim
174 
175 namespace tfc {
176 
177 void Log::associa(ostream & os, NivellLog n) {
178  destins_.push_back(shared_ptr<DestiLogging>(new DestiOstream(os, n)));
179 }
180 
181 void Log::associa(const fs::path & p, NivellLog n) throw (ErrorLogNoValid) {
182  destins_.push_back(shared_ptr<DestiLogging>(new DestiFitxer(p, n)));
183  // DestiFitxer -> throws ErrorLogNoValid
184 }
185 
186 void Log::desassocia(ostream &) {
187  throw ErrorNoImplementat(FITXER_I_LINIA_); // FIXME: Implementar
188 }
189 
190 // Implementació de Log::nivell_sortida(<T>, NivellLog)
191 template<typename TIt, typename TImpl>
192  void nivell_sortida_i(TIt beg, TIt end, const TImpl & d, NivellLog nn)
193  throw (ErrorDestiNoAssociat)
194 {
195  auto it = find_if(beg, end, FunctorCoincideix<TImpl>(d));
196  if (it == end) {
197  throw ErrorDestiNoAssociat();
198  }
199  (*it)->nivell(nn);
200 }
201 
202 // Implementació de nivell_sortida(<T>)
203 template<typename TIt, typename TImpl>
204  NivellLog nivell_sortida_i(TIt beg, TIt end, const TImpl & d)
205  throw (ErrorDestiNoAssociat)
206 {
207  auto it = find_if(beg, end, FunctorCoincideix<TImpl>(d));
208  if (it == end) {
209  throw ErrorDestiNoAssociat();
210  }
211  return (*it)->nivell();
212 }
213 
214 void Log::nivell_sortida(const ostream & d, NivellLog nn) throw (ErrorDestiNoAssociat) {
215  nivell_sortida_i(destins_.begin(), destins_.end(), d, nn);
216 }
217 
218 void Log::nivell_sortida(const fs::path & d, NivellLog nn) throw (ErrorDestiNoAssociat) {
219  nivell_sortida_i(destins_.begin(), destins_.end(), d, nn);
220 }
221 
222 NivellLog Log::nivell_sortida(const ostream & d) const throw (ErrorDestiNoAssociat) {
223  return nivell_sortida_i(destins_.begin(), destins_.end(), d);
224 }
225 
226 NivellLog Log::nivell_sortida(const fs::path & d) const throw (ErrorDestiNoAssociat) {
227  return nivell_sortida_i(destins_.begin(), destins_.end(), d);
228 }
229 
230 void Log::nivell_sortida(NivellLog nn) {
231  for_each(destins_.begin(), destins_.end(), FunctorCanviNivell(nn));
232 }
233 
234 // static
235 string Log::marca_de_temps() {
236  return utils::formata_data("%Y-%m-%d %H:%M:%S");
237 }
238 
239 // static
240 Log& Log::singleton() {
241  static Log l;
242  return l;
243 }
244 
245 // Impressió atòmica: Preparem la cadena a part i quan està llesta la imprimim
246 void Log::imprimeix(const MissatgeLog & ml) {
248  struct FunctorCommit {
249  const NivellLog nivell;
250  const string str;
251  void operator()(shared_ptr<DestiLogging> & desti) {
252  if (nivell >= desti->nivell()) {
253  desti->os() << str << flush;
254  }
255  }
256  FunctorCommit(NivellLog n, const string & s) : nivell(n), str(s) {}
257  };
258  if (ml.str().empty()) {
259  return;
260  }
261  ostringstream buffer;
262  buffer << "[" << marca_de_temps() << "] " << ml.str() << "\n";
263  FunctorCommit fc(ml.nivell(),buffer.str());
264  // XXX: No compila en G++ 4.4. Probablement part dels problemes què G++ 4.4 té amb
265  // les classes definides dins de funcions quan es passen a plantilles:
266  // for_each(destins_.begin(), destins_.end(), fc);
267  for (auto it=destins_.begin(); it != destins_.end(); ++it) {
268  fc(*it);
269  }
270 }
271 
273 //
274 // Manipuladors de logging
275 //
277 
278 void commit(MissatgeLog & ml) {
279  Log::singleton().imprimeix(ml);
280 }
281 
283  ml.oss_.str("");
284  return ml;
285 }
286 
287 // Interfície comuna de parametritzats
289 public:
290  virtual MissatgeLog& operator()(MissatgeLog &) const = 0;
291 };
292 
297 public:
299 
300  virtual MissatgeLog& operator()(MissatgeLog & ml) const {
301  ml.nivell(nivell);
302  return ml;
303  }
304 private:
306 };
307 
308 // Generador inserible
309 std::shared_ptr<ManipuladorParametritzat> nivell(NivellLog n) {
310  std::shared_ptr<ManipuladorParametritzat> p(new CanviNivellMissatge(n));
311  return p;
312 }
313 
314 MissatgeLog& MissatgeLog::operator<<(const std::shared_ptr<ManipuladorParametritzat> & manip) {
315  const ManipuladorParametritzat * pmanip = manip.get();
316  return (*pmanip)(*this);
317 }
318 
319 } // ns tfc
320 
321 // vim:set ts=4 et ai: //