/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 | } |