Line data Source code
1 : /*
2 : * Copyright (c) 2013-2019 Made to Order Software Corp. All Rights Reserved
3 : *
4 : * https://snapwebsites.org/project/snaplogger
5 : * contact@m2osw.com
6 : *
7 : * This program is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 2 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * This program is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License along
18 : * with this program; if not, write to the Free Software Foundation, Inc.,
19 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 : */
21 :
22 : /** \file
23 : * \brief Appenders are used to append data to somewhere.
24 : *
25 : * This file declares the base appender class.
26 : */
27 :
28 : // self
29 : //
30 : #include "snaplogger/file_appender.h"
31 :
32 : #include "snaplogger/guard.h"
33 : #include "snaplogger/map_diagnostic.h"
34 :
35 :
36 : // snapdev lib
37 : //
38 : #include <snapdev/lockfile.h>
39 :
40 :
41 : // C++ lib
42 : //
43 : #include <iostream>
44 :
45 :
46 : // C lib
47 : //
48 : #include <sys/types.h>
49 : #include <sys/stat.h>
50 : #include <fcntl.h>
51 : #include <unistd.h>
52 :
53 :
54 : // last include
55 : //
56 : #include <snapdev/poison.h>
57 :
58 :
59 :
60 : namespace snaplogger
61 : {
62 :
63 :
64 : namespace
65 : {
66 :
67 :
68 8 : APPENDER_FACTORY(file);
69 :
70 :
71 : }
72 : // no name namespace
73 :
74 :
75 :
76 0 : file_appender::file_appender(std::string const name)
77 0 : : appender(name, "file")
78 : {
79 0 : }
80 :
81 :
82 0 : file_appender::~file_appender()
83 : {
84 0 : }
85 :
86 :
87 0 : void file_appender::set_config(advgetopt::getopt const & opts)
88 : {
89 0 : appender::set_config(opts);
90 :
91 : // PATH
92 : //
93 0 : std::string const path_field(get_name() + "::path");
94 0 : if(opts.is_defined(path_field))
95 : {
96 0 : f_path = opts.get_string(path_field);
97 : }
98 0 : else if(opts.is_defined("path"))
99 : {
100 0 : f_path = opts.get_string("path");
101 : }
102 :
103 : // FILENAME
104 : //
105 0 : std::string const filename_field(get_name() + "::filename");
106 0 : if(opts.is_defined(filename_field))
107 : {
108 0 : f_filename = opts.get_string(filename_field);
109 : }
110 : // else -- we'll try to dynamically determine a filename when we
111 : // reach the send_message() function
112 :
113 : // LOCK
114 : //
115 0 : std::string const lock_field(get_name() + "::lock");
116 0 : if(opts.is_defined(lock_field))
117 : {
118 0 : f_lock = opts.get_string(lock_field) == "true";
119 : }
120 :
121 : // FLUSH
122 : //
123 0 : std::string const flush_field(get_name() + "::flush");
124 0 : if(opts.is_defined(flush_field))
125 : {
126 0 : f_flush = opts.get_string(flush_field) == "true";
127 : }
128 :
129 : // SECURE
130 : //
131 0 : std::string const secure_field(get_name() + "::secure");
132 0 : if(opts.is_defined(secure_field))
133 : {
134 0 : f_secure = opts.get_string(secure_field) != "false";
135 : }
136 :
137 : // FALLBACK TO CONSOLE
138 : //
139 0 : std::string const fallback_to_console_field(get_name() + "::fallback_to_console");
140 0 : if(opts.is_defined(fallback_to_console_field))
141 : {
142 0 : f_fallback_to_console = opts.get_string(fallback_to_console_field) == "true";
143 : }
144 0 : }
145 :
146 :
147 0 : void file_appender::reopen()
148 : {
149 0 : guard g;
150 :
151 0 : f_fd.reset();
152 0 : f_initialized = false;
153 0 : }
154 :
155 :
156 0 : void file_appender::set_filename(std::string const & filename)
157 : {
158 0 : if(f_filename != filename)
159 : {
160 0 : f_filename = filename;
161 0 : f_initialized = false;
162 : }
163 0 : }
164 :
165 :
166 0 : void file_appender::process_message(message const & msg, std::string const & formatted_message)
167 : {
168 0 : snap::NOTUSED(msg);
169 :
170 0 : guard g;
171 :
172 0 : if(!f_initialized)
173 : {
174 0 : f_initialized = true;
175 :
176 0 : if(f_filename.empty())
177 : {
178 : // try to generate a filename
179 : //
180 0 : map_diagnostics_t map(get_map_diagnostics());
181 0 : auto const it(map.find("progname"));
182 0 : if(it == map.end())
183 : {
184 0 : return;
185 : }
186 0 : if(it->second.empty())
187 : {
188 0 : return;
189 : }
190 :
191 0 : f_filename = f_path + "/";
192 0 : if(f_secure)
193 : {
194 0 : f_filename += "secure/";
195 : }
196 0 : f_filename += it->second;
197 0 : f_filename += ".log";
198 : }
199 0 : else if(f_filename.find('/') == std::string::npos)
200 : {
201 0 : f_filename = f_path + "/" + f_filename;
202 : }
203 0 : std::string::size_type pos(f_filename.rfind('/'));
204 0 : if(pos == std::string::npos)
205 : {
206 0 : pos = 0;
207 : }
208 0 : if(f_filename.find('.', pos + 1) == std::string::npos)
209 : {
210 0 : f_filename += ".log";
211 : }
212 :
213 0 : if(access(f_filename.c_str(), R_OK | W_OK) != 0
214 0 : && errno != ENOENT)
215 : {
216 0 : return;
217 : }
218 :
219 0 : int flags(O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC | O_LARGEFILE | O_NOCTTY);
220 0 : int mode(S_IRUSR | S_IWUSR);
221 0 : if(!f_secure)
222 : {
223 0 : mode |= S_IRGRP;
224 : }
225 :
226 0 : f_fd.reset(open(f_filename.c_str(), flags, mode));
227 : }
228 :
229 0 : if(!f_fd)
230 : {
231 0 : return;
232 : }
233 :
234 0 : std::unique_ptr<snap::lockfd> lock_file;
235 0 : if(f_lock)
236 : {
237 0 : lock_file = std::make_unique<snap::lockfd>(f_fd.get(), snap::lockfd::mode_t::LOCKFILE_EXCLUSIVE);
238 : }
239 :
240 0 : ssize_t const l(write(f_fd.get(), formatted_message.c_str(), formatted_message.length()));
241 0 : if(static_cast<size_t>(l) != formatted_message.length())
242 : {
243 : // how could we report that? we are the logger...
244 0 : if(f_fallback_to_console
245 0 : && isatty(fileno(stdout)))
246 : {
247 0 : std::cout << formatted_message.c_str();
248 : }
249 : }
250 : }
251 :
252 :
253 :
254 :
255 :
256 6 : } // snaplogger namespace
257 : // vim: ts=4 sw=4 et
|