1 /*
2 ** Copyright 2011-2014 Centreon
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 **
16 ** For more information : contact@centreon.com
17 */
18
19 #include "com/centreon/logging/file.hh"
20 #include <cerrno>
21 #include <cstdlib>
22 #include <cstring>
23 #include "com/centreon/exceptions/basic.hh"
24 #include "com/centreon/misc/stringifier.hh"
25
26 using namespace com::centreon::logging;
27
28 /**
29 * Default constructor.
30 *
31 * @param[in] file The file to used.
32 * @param[in] is_sync Enable synchronization.
33 * @param[in] show_pid Enable show pid.
34 * @param[in] show_timestamp Enable show timestamp.
35 * @param[in] show_thread_id Enable show thread id.
36 * @param[in] max_size Maximum file size.
37 */
file(FILE * file,bool is_sync,bool show_pid,time_precision show_timestamp,bool show_thread_id,uint64_t max_size)38 file::file(FILE* file,
39 bool is_sync,
40 bool show_pid,
41 time_precision show_timestamp,
42 bool show_thread_id,
43 uint64_t max_size)
44 : backend(is_sync, show_pid, show_timestamp, show_thread_id),
45 _max_size(max_size),
46 _out(file),
47 _size(0) {}
48
49 /**
50 * Constructor with file path name.
51 *
52 * @param[in] path The path of the file to used.
53 * @param[in] is_sync Enable synchronization.
54 * @param[in] show_pid Enable show pid.
55 * @param[in] show_timestamp Enable show timestamp.
56 * @param[in] show_thread_id Enable show thread id.
57 * @param[in] max_size Maximum file size.
58 */
file(std::string const & path,bool is_sync,bool show_pid,time_precision show_timestamp,bool show_thread_id,uint64_t max_size)59 file::file(std::string const& path,
60 bool is_sync,
61 bool show_pid,
62 time_precision show_timestamp,
63 bool show_thread_id,
64 uint64_t max_size)
65 : backend(is_sync, show_pid, show_timestamp, show_thread_id),
66 _max_size(max_size),
67 _path(path),
68 _out(NULL),
69 _size(0) {
70 open();
71 }
72
73 /**
74 * Default destructor.
75 */
~file()76 file::~file() noexcept {
77 close();
78 }
79
80 /**
81 * Close file.
82 */
close()83 void file::close() noexcept {
84 std::lock_guard<std::recursive_mutex> lock(_lock);
85
86 if (!_out || _out == stdout || _out == stderr)
87 return;
88
89 int ret;
90 do {
91 ret = fclose(_out);
92 } while (ret == -1 && errno == EINTR);
93 _out = NULL;
94 }
95
96 /**
97 * Get filename.
98 *
99 * @return The filename string.
100 */
filename() const101 std::string const& file::filename() const noexcept {
102 return (_path);
103 }
104
105 /**
106 * Write message into the file.
107 * @remark This method is thread safe.
108 *
109 * @param[in] type Logging types.
110 * @param[in] verbose Verbosity level.
111 * @param[in] msg The message to write.
112 * @param[in] size The message's size.
113 */
log(uint64_t types,uint32_t verbose,char const * msg,uint32_t size)114 void file::log(uint64_t types,
115 uint32_t verbose,
116 char const* msg,
117 uint32_t size) noexcept {
118 (void)types;
119 (void)verbose;
120 (void)size;
121
122 misc::stringifier header;
123 _build_header(header);
124
125 // Split msg by line.
126 misc::stringifier buffer;
127 uint32_t i(0);
128 uint32_t last(0);
129 while (msg[i]) {
130 if (msg[i] == '\n') {
131 buffer << header;
132 buffer.append(msg + last, i - last) << "\n";
133 last = i + 1;
134 }
135 ++i;
136 }
137 if (last != i) {
138 buffer << header;
139 buffer.append(msg + last, i - last) << "\n";
140 }
141
142 std::lock_guard<std::recursive_mutex> lock(_lock);
143 if (_out) {
144 // Size control.
145 if ((_max_size > 0) && (_size + buffer.size() > _max_size))
146 _max_size_reached();
147 _size += buffer.size();
148
149 // Physical write.
150 size_t ret;
151 do {
152 clearerr(_out);
153 ret = fwrite(buffer.data(), buffer.size(), 1, _out);
154 } while (ret != 1 && ferror(_out) && errno == EINTR);
155
156 // Flush data if is necessary.
157 while (_is_sync && fflush(_out) < 0 && errno == EINTR)
158 ;
159 }
160 }
161
162 /**
163 * Open file.
164 */
open()165 void file::open() {
166 std::lock_guard<std::recursive_mutex> lock(_lock);
167
168 if (_out && _path.empty())
169 return;
170
171 if (!(_out = fopen(_path.c_str(), "a")))
172 throw(basic_error() << "failed to open file '" << _path
173 << "': " << strerror(errno));
174 _size = ftell(_out);
175
176 return;
177 }
178
179 /**
180 * Close and open file.
181 */
reopen()182 void file::reopen() {
183 std::lock_guard<std::recursive_mutex> lock(_lock);
184
185 if (!_out || _out == stdout || _out == stderr)
186 return;
187
188 int ret;
189 do {
190 ret = fclose(_out);
191 } while (ret == -1 && errno == EINTR);
192
193 if (!(_out = fopen(_path.c_str(), "a")))
194 throw(basic_error() << "failed to open file '" << _path
195 << "': " << strerror(errno));
196 _size = ftell(_out);
197
198 return;
199 }
200
201 /**
202 * Method called when max size is reached.
203 */
_max_size_reached()204 void file::_max_size_reached() {
205 if (!_out || _out == stdout || _out == stderr)
206 return;
207
208 int ret;
209 do {
210 ret = fclose(_out);
211 } while (ret == -1 && errno == EINTR);
212
213 remove(_path.c_str());
214
215 if (!(_out = fopen(_path.c_str(), "a")))
216 throw(basic_error() << "failed to open file '" << _path
217 << "': " << strerror(errno));
218 _size = ftell(_out);
219 }
220