1 /** @file
2
3 A brief file description
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22 */
23
24 #pragma once
25
26 #include "tscore/ink_platform.h"
27 #include "Log.h"
28 #include "LogFile.h"
29 #include "LogFormat.h"
30 #include "LogFilter.h"
31 #include "LogBuffer.h"
32 #include "LogAccess.h"
33 #include "LogFilter.h"
34 #include <vector>
35
36 /*-------------------------------------------------------------------------
37 LogObject
38
39 This is a new addition to the Traffic Server logging as of the 3.1
40 (Panda) release. This object corresponds to the new type of logfile
41 entity that will be the focal point for all logging, replacing the role
42 of the LogFormat object. The LogObject will contain information about
43 the format being used, the physical file attached, and any filters that
44 are in place. The global logging configuration for a traffic server will
45 consist of a list of LogObjects.
46 -------------------------------------------------------------------------*/
47
48 #define LOG_FILE_ASCII_OBJECT_FILENAME_EXTENSION ".log"
49 #define LOG_FILE_BINARY_OBJECT_FILENAME_EXTENSION ".blog"
50 #define LOG_FILE_PIPE_OBJECT_FILENAME_EXTENSION ".pipe"
51
52 #define FLUSH_ARRAY_SIZE (512 * 4)
53
54 #define LOG_OBJECT_ARRAY_DELTA 8
55
56 #define ACQUIRE_API_MUTEX(_f) \
57 ink_mutex_acquire(_APImutex); \
58 Debug("log-api-mutex", _f)
59
60 #define RELEASE_API_MUTEX(_f) \
61 ink_mutex_release(_APImutex); \
62 Debug("log-api-mutex", _f)
63
64 class LogBufferManager
65 {
66 private:
67 ASLL(LogBuffer, write_link) write_list;
68 int _num_flush_buffers = 0;
69
70 public:
LogBufferManager()71 LogBufferManager() {}
72 inline void
add_to_flush_queue(LogBuffer * buffer)73 add_to_flush_queue(LogBuffer *buffer)
74 {
75 write_list.push(buffer);
76 ink_atomic_increment(&_num_flush_buffers, 1);
77 }
78
79 size_t preproc_buffers(LogBufferSink *sink);
80 };
81
82 // LogObject is atomically reference counted, and the reference count is always owned by
83 // one or more LogObjectManagers.
84 class LogObject : public RefCountObj
85 {
86 public:
87 enum LogObjectFlags {
88 BINARY = 1,
89 WRITES_TO_PIPE = 4,
90 LOG_OBJECT_FMT_TIMESTAMP = 8, // always format a timestamp into each log line (for raw text logs)
91 };
92
93 // BINARY: log is written in binary format (rather than ascii)
94 // WRITES_TO_PIPE: object writes to a named pipe rather than to a file
95
96 LogObject(LogConfig *cfg, const LogFormat *format, const char *log_dir, const char *basename, LogFileFormat file_format,
97 const char *header, Log::RollingEnabledValues rolling_enabled, int flush_threads, int rolling_interval_sec = 0,
98 int rolling_offset_hr = 0, int rolling_size_mb = 0, bool auto_created = false, int rolling_max_count = 0,
99 int rolling_min_count = 0, bool reopen_after_rolling = false, int pipe_buffer_size = 0);
100 ~LogObject() override;
101
102 void add_filter(LogFilter *filter, bool copy = true);
103 void set_filter_list(const LogFilterList &list, bool copy = true);
104
105 inline void
set_fmt_timestamps()106 set_fmt_timestamps()
107 {
108 m_flags |= LOG_OBJECT_FMT_TIMESTAMP;
109 }
110
111 int log(LogAccess *lad, const char *text_entry = nullptr);
112
113 /** Log the @a text_entry.
114 *
115 * @param lad Log accessor.
116 * @param text_entry Literal text to log.
117 * @return Result - value from Log::ReturnCodeFlags.
118 *
119 * @see Log::ReturnCodeFlags.
120 */
121 int log(LogAccess *lad, std::string_view text_entry);
122
123 int va_log(LogAccess *lad, const char *fmt, va_list ap);
124
125 unsigned roll_files(long time_now = 0);
126
127 inline int
add_to_flush_queue(LogBuffer * buffer)128 add_to_flush_queue(LogBuffer *buffer)
129 {
130 int idx = m_buffer_manager_idx++ % m_flush_threads;
131
132 m_buffer_manager[idx].add_to_flush_queue(buffer);
133
134 return idx;
135 }
136
137 inline size_t
138 preproc_buffers(int idx = -1)
139 {
140 size_t nfb;
141
142 if (idx == -1) {
143 idx = m_buffer_manager_idx++ % m_flush_threads;
144 }
145
146 nfb = m_buffer_manager[idx].preproc_buffers(m_logFile.get());
147
148 return nfb;
149 }
150
151 void check_buffer_expiration(long time_now);
152
153 void display(FILE *fd = stdout);
154 static uint64_t compute_signature(LogFormat *format, char *filename, unsigned int flags);
155
156 inline const char *
get_original_filename()157 get_original_filename() const
158 {
159 return m_filename;
160 }
161 inline const char *
get_full_filename()162 get_full_filename() const
163 {
164 return (m_alt_filename ? m_alt_filename : m_filename);
165 }
166 inline const char *
get_base_filename()167 get_base_filename() const
168 {
169 return m_basename;
170 }
171
172 off_t get_file_size_bytes();
173
174 inline uint64_t
get_signature()175 get_signature() const
176 {
177 return m_signature;
178 }
179
180 inline int
get_rolling_interval()181 get_rolling_interval() const
182 {
183 return m_rolling_interval_sec;
184 }
185
186 inline void
set_log_file_header(const char * header)187 set_log_file_header(const char *header)
188 {
189 m_logFile->change_header(header);
190 }
191
192 inline void
set_rolling_enabled(Log::RollingEnabledValues rolling_enabled)193 set_rolling_enabled(Log::RollingEnabledValues rolling_enabled)
194 {
195 _setup_rolling(Log::config, rolling_enabled, m_rolling_interval_sec, m_rolling_offset_hr, m_rolling_size_mb);
196 }
197
198 inline void
set_rolling_interval_sec(int rolling_interval_sec)199 set_rolling_interval_sec(int rolling_interval_sec)
200 {
201 _setup_rolling(Log::config, m_rolling_enabled, rolling_interval_sec, m_rolling_offset_hr, m_rolling_size_mb);
202 }
203
204 inline void
set_rolling_offset_hr(int rolling_offset_hr)205 set_rolling_offset_hr(int rolling_offset_hr)
206 {
207 _setup_rolling(Log::config, m_rolling_enabled, m_rolling_interval_sec, rolling_offset_hr, m_rolling_size_mb);
208 }
209
210 inline void
set_rolling_size_mb(int rolling_size_mb)211 set_rolling_size_mb(int rolling_size_mb)
212 {
213 _setup_rolling(Log::config, m_rolling_enabled, m_rolling_interval_sec, m_rolling_offset_hr, rolling_size_mb);
214 }
215
216 inline bool
writes_to_pipe()217 writes_to_pipe() const
218 {
219 return (m_flags & WRITES_TO_PIPE) ? true : false;
220 }
221 inline bool
writes_to_disk()222 writes_to_disk()
223 {
224 return (m_logFile && !(m_flags & WRITES_TO_PIPE) ? true : false);
225 }
226
227 inline unsigned int
get_flags()228 get_flags() const
229 {
230 return m_flags;
231 }
232
233 void rename(char *new_name);
234
235 inline bool
has_alternate_name()236 has_alternate_name() const
237 {
238 return (m_alt_filename ? true : false);
239 }
240
241 inline const char *
get_format_string()242 get_format_string()
243 {
244 return (m_format ? m_format->format_string() : "<none>");
245 }
246
247 inline void
force_new_buffer()248 force_new_buffer()
249 {
250 _checkout_write(nullptr, 0);
251 }
252
253 bool operator==(LogObject &rhs);
254
255 public:
256 LogFormat *m_format;
257 Ptr<LogFile> m_logFile;
258 LogFilterList m_filter_list;
259
260 private:
261 char *m_basename; // the name of the file associated
262 // with this object, relative to
263 // the logging directory
264 char *m_filename; // the full path of the file associated
265 // with this object
266 char *m_alt_filename; // the full path of the file used
267 // instead of m_filename if the latter
268 // could not be used because of
269 // name conflicts
270
271 unsigned int m_flags; // diverse object flags (see above)
272 uint64_t m_signature; // INK_MD5 signature for object
273
274 Log::RollingEnabledValues m_rolling_enabled;
275 int m_flush_threads; // number of flush threads
276 int m_rolling_interval_sec; // time interval between rolls
277 // 0 means no rolling
278 int m_rolling_offset_hr; //
279 int m_rolling_size_mb; // size at which the log file rolls
280 long m_last_roll_time; // the last time this object rolled its files
281 int m_max_rolled; // maximum number of rolled logs to be kept, 0 no limit
282 int m_min_rolled; // minimum number of rolled logs to be kept, 0 no limit
283 bool m_reopen_after_rolling; // reopen log file after rolling (normally it is just renamed and closed)
284
285 head_p m_log_buffer; // current work buffer
286 unsigned m_buffer_manager_idx;
287 LogBufferManager *m_buffer_manager;
288
289 int m_pipe_buffer_size;
290
291 void generate_filenames(const char *log_dir, const char *basename, LogFileFormat file_format);
292 void _setup_rolling(LogConfig *cfg, Log::RollingEnabledValues rolling_enabled, int rolling_interval_sec, int rolling_offset_hr,
293 int rolling_size_mb);
294 unsigned _roll_files(long interval_start, long interval_end);
295
296 LogBuffer *_checkout_write(size_t *write_offset, size_t write_size);
297
298 // noncopyable
299 LogObject(const LogObject &) = delete;
300 LogObject &operator=(const LogObject &) = delete;
301
302 private:
303 // -- member functions not allowed --
304 LogObject();
305 };
306
307 /*-------------------------------------------------------------------------
308 TextLog
309 -------------------------------------------------------------------------*/
310
311 class TextLogObject : public LogObject
312 {
313 public:
314 inkcoreapi TextLogObject(const char *name, const char *log_dir, bool timestamps, const char *header,
315 Log::RollingEnabledValues rolling_enabled, int flush_threads, int rolling_interval_sec,
316 int rolling_offset_hr, int rolling_size_mb, int rolling_max_count, int rolling_min_count,
317 bool reopen_after_rolling);
318
319 inkcoreapi int write(const char *format, ...) TS_PRINTFLIKE(2, 3);
320 inkcoreapi int va_write(const char *format, va_list ap);
321
322 static const LogFormat *textfmt;
323 };
324
325 /*-------------------------------------------------------------------------
326 LogObjectManager
327
328 A log object manager keeps track of log objects and is responsible for
329 their deletion
330 -------------------------------------------------------------------------*/
331
332 class LogObjectManager
333 {
334 public:
335 // error status
336 //
337 enum {
338 NO_FILENAME_CONFLICTS = 0,
339 ERROR_ACCESSING_LOG_FILE,
340 ERROR_DETERMINING_FILE_INFO,
341 CANNOT_SOLVE_FILENAME_CONFLICTS,
342 ERROR_DOING_FILESYSTEM_CHECKS
343 };
344
345 private:
346 typedef std::vector<LogObject *> LogObjectList;
347
348 LogObjectList _objects; // array of configured objects
349 LogObjectList _APIobjects; // array of API objects
350
351 public:
352 ink_mutex *_APImutex; // synchronize access to array of API objects
353 private:
354 int _manage_object(LogObject *log_object, bool is_api_object, int maxConflicts);
355 static bool _has_internal_filename_conflict(const char *filename, LogObjectList &objects);
356 int _solve_filename_conflicts(LogObject *log_obj, int maxConflicts);
357 int _solve_internal_filename_conflicts(LogObject *log_obj, int maxConflicts, int fileNum = 0);
358 void _filename_resolution_abort(const char *fname);
359
360 public:
361 LogObjectManager();
362 ~LogObjectManager();
363
364 // we don't define a destructor because the objects that the
365 // LogObjectManager manages are either passed along to another
366 // manager or moved to the list of inactive objects to be destroyed
367
368 int
369 manage_object(LogObject *logObject, int maxConflicts = 99)
370 {
371 return _manage_object(logObject, false, maxConflicts);
372 }
373
374 int
375 manage_api_object(LogObject *logObject, int maxConflicts = 99)
376 {
377 return _manage_object(logObject, true, maxConflicts);
378 }
379
380 // return success
381 bool unmanage_api_object(LogObject *logObject);
382
383 // Flush the buffers on all the managed log objects.
384 void flush_all_objects();
385
386 LogObject *get_object_with_signature(uint64_t signature);
387 void check_buffer_expiration(long time_now);
388
389 unsigned roll_files(long time_now);
390 void reopen_moved_log_files();
391
392 int log(LogAccess *lad);
393 void display(FILE *str = stdout);
394 void add_filter_to_all(LogFilter *filter);
395 LogObject *find_by_format_name(const char *name) const;
396 size_t preproc_buffers(int idx);
397 void open_local_pipes();
398 void transfer_objects(LogObjectManager &mgr);
399
400 bool
has_api_objects()401 has_api_objects() const
402 {
403 return _APIobjects.size() > 0;
404 }
405 unsigned
get_num_objects()406 get_num_objects() const
407 {
408 return _objects.size();
409 }
410 };
411
412 inline bool
413 LogObject::operator==(LogObject &old)
414 {
415 return (get_signature() == old.get_signature() && m_logFile && old.m_logFile &&
416 strcmp(m_logFile->get_name(), old.m_logFile->get_name()) == 0 && (m_filter_list == old.m_filter_list) &&
417 (m_rolling_interval_sec == old.m_rolling_interval_sec && m_rolling_offset_hr == old.m_rolling_offset_hr &&
418 m_rolling_size_mb == old.m_rolling_size_mb && m_reopen_after_rolling == old.m_reopen_after_rolling &&
419 m_max_rolled == old.m_max_rolled && m_min_rolled == old.m_min_rolled));
420 }
421
422 inline off_t
get_file_size_bytes()423 LogObject::get_file_size_bytes()
424 {
425 return m_logFile->get_size_bytes();
426 }
427