logging.cpp 5.46 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
 * @date Tue Jan 18 17:07:26 2011 +0100
 * @author André Anjos <andre.anjos@idiap.ch>
 *
 * @brief Implements all logging infrastructure.
 *
 * Copyright (C) Idiap Research Institute, Martigny, Switzerland
 */

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <boost/filesystem.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/shared_array.hpp>
#include <boost/make_shared.hpp>

#ifdef _WIN32
#include <io.h> //definition of mktemp
#endif

/**
 * MT "lock" support was only introduced in Boost 1.35. Before copying this
 * very ugly hack, make sure we are still using Boost 1.34. This will no longer
 * be the case starting January 2011.
 */
#include <boost/version.hpp>
#include <boost/thread/mutex.hpp>
#if ((BOOST_VERSION / 100) % 1000) > 34
#include <boost/thread/locks.hpp>
#else
#warning Disabling MT locks because Boost < 1.35!
#endif

37
#include <bob.core/logging.h>
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

bob::core::OutputDevice::~OutputDevice() {}

struct NullOutputDevice: public bob::core::OutputDevice {
  virtual ~NullOutputDevice() {}
  virtual std::streamsize write(const char*, std::streamsize n) {
    return n;
  }
};

struct StdoutOutputDevice: public bob::core::OutputDevice {
  virtual ~StdoutOutputDevice() {}
  virtual std::streamsize write(const char* s, std::streamsize n) {
    static boost::mutex mutex;
#if ((BOOST_VERSION / 100) % 1000) > 35
    boost::lock_guard<boost::mutex> lock(mutex);
#endif
    std::cout.write(s, n);
    return n;
  }
};

struct StderrOutputDevice: public bob::core::OutputDevice {
  virtual ~StderrOutputDevice() {}
  virtual std::streamsize write(const char* s, std::streamsize n) {
    static boost::mutex mutex;
#if ((BOOST_VERSION / 100) % 1000) > 35
    boost::lock_guard<boost::mutex> lock(mutex);
#endif
    std::cerr.write(s, n);
    return n;
  }
};

/**
 * Determines if the input filename ends in ".gz"
 *
 * @param filename The name of the file to be analyzed.
 */
inline static bool is_dot_gz(const std::string& filename) {
  return boost::filesystem::path(filename).extension() == ".gz";
}

struct FileOutputDevice: public bob::core::OutputDevice {
  FileOutputDevice(const std::string& filename)
    : m_filename(filename),
      m_file(),
      m_ostream(new boost::iostreams::filtering_ostream),
      m_mutex(new boost::mutex)
  {
    //this first bit creates the output file handle
    std::ios_base::openmode mode = std::ios_base::out | std::ios_base::trunc;
    if (is_dot_gz(filename)) mode |= std::ios_base::binary;
    m_file = boost::make_shared<std::ofstream>(filename.c_str(), mode);
    //this second part configures gzip'ing if necessary and associates the
    //output file with the filtering stream.
    if (is_dot_gz(filename))
      m_ostream->push(boost::iostreams::basic_gzip_compressor<>());
    m_ostream->push(*m_file);
  }

  FileOutputDevice(const FileOutputDevice& other)
    : m_filename(other.m_filename),
      m_file(other.m_file),
      m_ostream(other.m_ostream),
      m_mutex(other.m_mutex)
  {
  }

  virtual ~FileOutputDevice() {}

  virtual std::streamsize write(const char* s, std::streamsize n) {
#if ((BOOST_VERSION / 100) % 1000) > 35
    boost::lock_guard<boost::mutex> lock(*m_mutex);
#endif
    m_ostream->write(s, n);
    return n;
  }

  //internal representation
  private:
    std::string m_filename; ///< the name of the file I'm writing to
    boost::shared_ptr<std::ofstream> m_file; ///< the file output stream
    boost::shared_ptr<boost::iostreams::filtering_ostream> m_ostream; ///< the output stream
    boost::shared_ptr<boost::mutex> m_mutex; ///< multi-threading guardian

};

bool bob::core::debug_level(unsigned int i) {
  const char* value = getenv("BOB_DEBUG");
  if (!value) return false;
  unsigned long v = strtoul(value, 0, 0);
  if (v < 1 || v > 3) v = 0;
  return (i <= v);
}


bob::core::AutoOutputDevice::AutoOutputDevice()
: m_device(new NullOutputDevice)
{
}

bob::core::AutoOutputDevice::AutoOutputDevice(const std::string& configuration)
: m_device()
{
143
  reset(configuration);
144
145
146
147
148
149
150
151
152
153
}

bob::core::AutoOutputDevice::AutoOutputDevice(boost::shared_ptr<OutputDevice> d)
: m_device(d)
{
}

bob::core::AutoOutputDevice::~AutoOutputDevice() {
}

154
155
156
157
158
159
160
161
162
163
void bob::core::AutoOutputDevice::reset(const std::string& configuration)
{
  std::string str(configuration);
  str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end());
  if (str == "null" || str.size()==0) m_device.reset(new NullOutputDevice);
  else if (str == "stdout") m_device.reset(new StdoutOutputDevice);
  else if (str == "stderr") m_device.reset(new StderrOutputDevice);
  else m_device.reset(new FileOutputDevice(configuration));
}

164
165
166
167
168
169
170
171
172
173
174
175
std::streamsize bob::core::AutoOutputDevice::write(const char* s, std::streamsize n) {
  return m_device->write(s, n);
}

void bob::core::AutoOutputDevice::close() {
  m_device->close();
}

boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::debug("stdout");
boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::info("stdout");
boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::warn("stderr");
boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::error("stderr");
176
177
178
179
180
181
182

void bob::core::log_level(bob::core::LOG_LEVEL level){
  bob::core::debug->reset(level == DEBUG ?  "stdout" : "null");
  bob::core::info->reset(level >= INFO && level < DISABLE ?  "stdout" : "null");
  bob::core::warn->reset(level >= WARNING && level < DISABLE ?  "stderr" : "null");
  bob::core::error->reset(level >= ERROR && level < DISABLE ?  "stderr" : "null");
}