Coverage Report

Created: 2026-10-31 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/trafficserver/include/proxy/logging/LogObject.h
Line
Count
Source
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 "proxy/logging/Log.h"
28
#include "proxy/logging/LogFile.h"
29
#include "proxy/logging/LogFormat.h"
30
#include "proxy/logging/LogFilter.h"
31
#include "proxy/logging/LogBuffer.h"
32
#include "proxy/logging/LogAccess.h"
33
#include "proxy/logging/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
0
#define LOG_FILE_ASCII_OBJECT_FILENAME_EXTENSION  ".log"
49
0
#define LOG_FILE_BINARY_OBJECT_FILENAME_EXTENSION ".blog"
50
0
#define LOG_FILE_PIPE_OBJECT_FILENAME_EXTENSION   ".pipe"
51
52
0
#define FLUSH_ARRAY_SIZE (512 * 4)
53
54
#define LOG_OBJECT_ARRAY_DELTA 8
55
56
#define ACQUIRE_API_MUTEX(_f)   \
57
0
  ink_mutex_acquire(_APImutex); \
58
0
  Dbg(_APImutex_dbg_ctl(), _f)
59
60
#define RELEASE_API_MUTEX(_f)   \
61
0
  ink_mutex_release(_APImutex); \
62
0
  Dbg(_APImutex_dbg_ctl(), _f)
63
64
class LogBufferManager
65
{
66
private:
67
  ASLL(LogBuffer, write_link) write_list;
68
  int _num_flush_buffers = 0;
69
70
public:
71
0
  LogBufferManager() {}
72
  inline void
73
  add_to_flush_queue(LogBuffer *buffer)
74
0
  {
75
0
    write_list.push(buffer);
76
0
    ink_atomic_increment(&_num_flush_buffers, 1);
77
0
  }
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 RefCountObjInHeap
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, bool m_fast = false,
100
            unsigned binary_log_version = LOG_SEGMENT_VERSION);
101
  ~LogObject() override;
102
103
  void add_filter(LogFilter *filter, bool copy = true);
104
105
  inline void
106
  set_fmt_timestamps()
107
0
  {
108
0
    m_flags |= LOG_OBJECT_FMT_TIMESTAMP;
109
0
  }
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 size_t
128
  preproc_buffers(int idx = -1)
129
0
  {
130
0
    size_t nfb;
131
132
0
    if (idx == -1) {
133
0
      idx = m_buffer_manager_idx++ % m_flush_threads;
134
0
    }
135
136
0
    nfb = m_buffer_manager[idx].preproc_buffers(m_logFile.get());
137
138
0
    return nfb;
139
0
  }
140
141
  void check_buffer_expiration(long time_now);
142
143
  void            display(FILE *fd = stdout);
144
  static uint64_t compute_signature(LogFormat *format, char *filename, unsigned int flags);
145
146
  inline const char *
147
  get_original_filename() const
148
0
  {
149
0
    return m_filename;
150
0
  }
151
  inline const char *
152
  get_full_filename() const
153
0
  {
154
0
    return (m_alt_filename ? m_alt_filename : m_filename);
155
0
  }
156
  inline const char *
157
  get_base_filename() const
158
0
  {
159
0
    return m_basename;
160
0
  }
161
162
  off_t get_file_size_bytes();
163
164
  inline uint64_t
165
  get_signature() const
166
0
  {
167
0
    return m_signature;
168
0
  }
169
170
  inline int
171
  get_rolling_interval() const
172
0
  {
173
0
    return m_rolling_interval_sec;
174
0
  }
175
176
  inline void
177
  set_log_file_header(const char *header)
178
0
  {
179
0
    m_logFile->change_header(header);
180
0
  }
181
182
  inline void
183
  set_rolling_enabled(Log::RollingEnabledValues rolling_enabled)
184
0
  {
185
0
    _setup_rolling(Log::config, rolling_enabled, m_rolling_interval_sec, m_rolling_offset_hr, m_rolling_size_mb);
186
0
  }
187
188
  inline void
189
  set_rolling_interval_sec(int rolling_interval_sec)
190
0
  {
191
0
    _setup_rolling(Log::config, m_rolling_enabled, rolling_interval_sec, m_rolling_offset_hr, m_rolling_size_mb);
192
0
  }
193
194
  inline void
195
  set_rolling_offset_hr(int rolling_offset_hr)
196
0
  {
197
0
    _setup_rolling(Log::config, m_rolling_enabled, m_rolling_interval_sec, rolling_offset_hr, m_rolling_size_mb);
198
0
  }
199
200
  inline void
201
  set_rolling_size_mb(int rolling_size_mb)
202
0
  {
203
0
    _setup_rolling(Log::config, m_rolling_enabled, m_rolling_interval_sec, m_rolling_offset_hr, rolling_size_mb);
204
0
  }
205
206
  inline bool
207
  writes_to_pipe() const
208
0
  {
209
0
    return (m_flags & WRITES_TO_PIPE) ? true : false;
210
0
  }
211
  inline bool
212
  writes_to_disk()
213
0
  {
214
0
    return (m_logFile && !(m_flags & WRITES_TO_PIPE) ? true : false);
215
0
  }
216
217
  inline unsigned int
218
  get_flags() const
219
0
  {
220
0
    return m_flags;
221
0
  }
222
223
  // On-disk binary segment version (logging.yaml "binary_log_version"); 2 emits
224
  // the pre-v3 layout. Binary logs only; defaults to the current version. Set at
225
  // construction (before the first buffer header is stamped), not afterward.
226
  inline unsigned
227
  get_binary_log_version() const
228
0
  {
229
0
    return m_binary_log_version;
230
0
  }
231
232
  void rename(char *new_name);
233
234
  inline bool
235
  has_alternate_name() const
236
0
  {
237
0
    return (m_alt_filename ? true : false);
238
0
  }
239
240
  inline const char *
241
  get_format_string()
242
0
  {
243
0
    return (m_format ? m_format->format_string() : "<none>");
244
0
  }
245
246
  inline void
247
  force_new_buffer()
248
0
  {
249
0
    _checkout_write(nullptr, 0);
250
0
  }
251
252
  void flush_buffer(LogBuffer *);
253
254
  bool operator==(LogObject &rhs);
255
256
public:
257
  std::unique_ptr<LogFormat> m_format;
258
  Ptr<LogFile>               m_logFile;
259
  LogFilterList              m_filter_list;
260
261
private:
262
  char *m_basename; // the name of the file associated
263
  // with this object, relative to
264
  // the logging directory
265
  char *m_filename; // the full path of the file associated
266
  // with this object
267
  char *m_alt_filename; // the full path of the file used
268
  // instead of m_filename if the latter
269
  // could not be used because of
270
  // name conflicts
271
272
  unsigned int m_flags;                                    // diverse object flags (see above)
273
  uint64_t     m_signature;                                // INK_MD5 signature for object
274
  unsigned     m_binary_log_version = LOG_SEGMENT_VERSION; // on-disk binary segment version (logging.yaml "binary_log_version")
275
276
  Log::RollingEnabledValues m_rolling_enabled;
277
  int                       m_flush_threads;        // number of flush threads
278
  int                       m_rolling_interval_sec; // time interval between rolls
279
  // 0 means no rolling
280
  int  m_rolling_offset_hr;    //
281
  int  m_rolling_size_mb;      // size at which the log file rolls
282
  long m_last_roll_time;       // the last time this object rolled its files
283
  int  m_max_rolled;           // maximum number of rolled logs to be kept, 0 no limit
284
  int  m_min_rolled;           // minimum number of rolled logs to be kept, 0 no limit
285
  bool m_reopen_after_rolling; // reopen log file after rolling (normally it is just renamed and closed)
286
287
  head_p            m_log_buffer; // current work buffer
288
  unsigned          m_buffer_manager_idx;
289
  LogBufferManager *m_buffer_manager;
290
291
  int  m_pipe_buffer_size;
292
  bool m_fast; // use fast buffering (thread local logbuffers)
293
294
  void generate_filenames(const char *log_dir, const char *basename, LogFileFormat file_format);
295
  void _setup_rolling(LogConfig *cfg, Log::RollingEnabledValues rolling_enabled, int rolling_interval_sec, int rolling_offset_hr,
296
                      int rolling_size_mb);
297
  unsigned _roll_files(long interval_start, long interval_end);
298
299
  LogBuffer *_checkout_write(size_t *write_offset, size_t write_size);
300
301
  // noncopyable
302
  LogObject(const LogObject &)            = delete;
303
  LogObject &operator=(const LogObject &) = delete;
304
305
private:
306
  // -- member functions not allowed --
307
  LogObject();
308
};
309
310
/*-------------------------------------------------------------------------
311
  TextLog
312
  -------------------------------------------------------------------------*/
313
314
class TextLogObject : public LogObject
315
{
316
public:
317
  TextLogObject(const char *name, const char *log_dir, bool timestamps, const char *header,
318
                Log::RollingEnabledValues rolling_enabled, int flush_threads, int rolling_interval_sec, int rolling_offset_hr,
319
                int rolling_size_mb, int rolling_max_count, int rolling_min_count, bool reopen_after_rolling, bool fast = false);
320
321
  int write(const char *format, ...) TS_PRINTFLIKE(2, 3);
322
  int va_write(const char *format, va_list ap);
323
324
  static const LogFormat *textfmt;
325
};
326
327
/*-------------------------------------------------------------------------
328
  LogObjectManager
329
330
  A log object manager keeps track of log objects and is responsible for
331
  their deletion
332
  -------------------------------------------------------------------------*/
333
334
class LogObjectManager
335
{
336
public:
337
  // error status
338
  //
339
  enum {
340
    NO_FILENAME_CONFLICTS = 0,
341
    ERROR_ACCESSING_LOG_FILE,
342
    ERROR_DETERMINING_FILE_INFO,
343
    CANNOT_SOLVE_FILENAME_CONFLICTS,
344
    ERROR_DOING_FILESYSTEM_CHECKS
345
  };
346
347
private:
348
  using LogObjectList = std::vector<LogObject *>;
349
350
  LogObjectList _objects;    // array of configured objects
351
  LogObjectList _APIobjects; // array of API objects
352
353
public:
354
  ink_mutex *_APImutex; // synchronize access to array of API objects
355
  static DbgCtl &
356
  _APImutex_dbg_ctl()
357
0
  {
358
0
    static DbgCtl dc{"log-api-mutex"};
359
0
    return dc;
360
0
  }
361
362
private:
363
  int         _manage_object(LogObject *log_object, bool is_api_object, int maxConflicts);
364
  static bool _has_internal_filename_conflict(std::string_view filename, LogObjectList &objects);
365
  int         _solve_filename_conflicts(LogObject *log_obj, int maxConflicts);
366
  int         _solve_internal_filename_conflicts(LogObject *log_obj, int maxConflicts, int fileNum = 0);
367
  void        _filename_resolution_abort(const char *fname);
368
369
public:
370
  LogObjectManager();
371
  ~LogObjectManager();
372
373
  // we don't define a destructor because the objects that the
374
  // LogObjectManager manages are either passed along to another
375
  // manager or moved to the list of inactive objects to be destroyed
376
377
  int
378
  manage_object(LogObject *logObject, int maxConflicts = 99)
379
0
  {
380
0
    return _manage_object(logObject, false, maxConflicts);
381
0
  }
382
383
  int
384
  manage_api_object(LogObject *logObject, int maxConflicts = 99)
385
0
  {
386
0
    return _manage_object(logObject, true, maxConflicts);
387
0
  }
388
389
  // return success
390
  bool unmanage_api_object(LogObject *logObject);
391
392
  // Flush the buffers on all the managed log objects.
393
  void flush_all_objects();
394
395
  LogObject *get_object_with_signature(uint64_t signature);
396
  void       check_buffer_expiration(long time_now);
397
398
  unsigned roll_files(long time_now);
399
  void     reopen_moved_log_files();
400
401
  int        log(LogAccess *lad);
402
  void       display(FILE *str = stdout);
403
  void       add_filter_to_all(LogFilter *filter);
404
  LogObject *find_by_format_name(const char *name) const;
405
  size_t     preproc_buffers(int idx);
406
  void       open_local_pipes();
407
  void       transfer_objects(LogObjectManager &mgr);
408
409
  bool
410
  has_api_objects() const
411
0
  {
412
0
    return _APIobjects.size() > 0;
413
0
  }
414
  unsigned
415
  get_num_objects() const
416
0
  {
417
0
    return _objects.size();
418
0
  }
419
};
420
421
inline bool
422
LogObject::operator==(LogObject &old)
423
0
{
424
0
  return (get_signature() == old.get_signature() && m_logFile && old.m_logFile &&
425
0
          strcmp(m_logFile->get_name(), old.m_logFile->get_name()) == 0 && (m_filter_list == old.m_filter_list) &&
426
0
          (m_rolling_interval_sec == old.m_rolling_interval_sec && m_rolling_offset_hr == old.m_rolling_offset_hr &&
427
0
           m_rolling_size_mb == old.m_rolling_size_mb && m_reopen_after_rolling == old.m_reopen_after_rolling &&
428
0
           m_max_rolled == old.m_max_rolled && m_min_rolled == old.m_min_rolled));
429
0
}
430
431
inline off_t
432
LogObject::get_file_size_bytes()
433
0
{
434
0
  return m_logFile->get_size_bytes();
435
0
}