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