| /** @file |
| |
| A brief file description |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include "tscore/ink_platform.h" |
| #include "Log.h" |
| #include "LogFile.h" |
| #include "LogFormat.h" |
| #include "LogFilter.h" |
| #include "LogBuffer.h" |
| #include "LogAccess.h" |
| #include "LogFilter.h" |
| #include <vector> |
| |
| /*------------------------------------------------------------------------- |
| LogObject |
| |
| This is a new addition to the Traffic Server logging as of the 3.1 |
| (Panda) release. This object corresponds to the new type of logfile |
| entity that will be the focal point for all logging, replacing the role |
| of the LogFormat object. The LogObject will contain information about |
| the format being used, the physical file attached, and any filters that |
| are in place. The global logging configuration for a traffic server will |
| consist of a list of LogObjects. |
| -------------------------------------------------------------------------*/ |
| |
| #define LOG_FILE_ASCII_OBJECT_FILENAME_EXTENSION ".log" |
| #define LOG_FILE_BINARY_OBJECT_FILENAME_EXTENSION ".blog" |
| #define LOG_FILE_PIPE_OBJECT_FILENAME_EXTENSION ".pipe" |
| |
| #define FLUSH_ARRAY_SIZE (512 * 4) |
| |
| #define LOG_OBJECT_ARRAY_DELTA 8 |
| |
| #define ACQUIRE_API_MUTEX(_f) \ |
| ink_mutex_acquire(_APImutex); \ |
| Debug("log-api-mutex", _f) |
| |
| #define RELEASE_API_MUTEX(_f) \ |
| ink_mutex_release(_APImutex); \ |
| Debug("log-api-mutex", _f) |
| |
| class LogBufferManager |
| { |
| private: |
| ASLL(LogBuffer, write_link) write_list; |
| int _num_flush_buffers = 0; |
| |
| public: |
| LogBufferManager() {} |
| inline void |
| add_to_flush_queue(LogBuffer *buffer) |
| { |
| write_list.push(buffer); |
| ink_atomic_increment(&_num_flush_buffers, 1); |
| } |
| |
| size_t preproc_buffers(LogBufferSink *sink); |
| }; |
| |
| // LogObject is atomically reference counted, and the reference count is always owned by |
| // one or more LogObjectManagers. |
| class LogObject : public RefCountObj |
| { |
| public: |
| enum LogObjectFlags { |
| BINARY = 1, |
| WRITES_TO_PIPE = 4, |
| LOG_OBJECT_FMT_TIMESTAMP = 8, // always format a timestamp into each log line (for raw text logs) |
| }; |
| |
| // BINARY: log is written in binary format (rather than ascii) |
| // WRITES_TO_PIPE: object writes to a named pipe rather than to a file |
| |
| LogObject(LogConfig *cfg, const LogFormat *format, const char *log_dir, const char *basename, LogFileFormat file_format, |
| const char *header, Log::RollingEnabledValues rolling_enabled, int flush_threads, int rolling_interval_sec = 0, |
| int rolling_offset_hr = 0, int rolling_size_mb = 0, bool auto_created = false, int rolling_max_count = 0, |
| int rolling_min_count = 0, bool reopen_after_rolling = false, int pipe_buffer_size = 0); |
| ~LogObject() override; |
| |
| void add_filter(LogFilter *filter, bool copy = true); |
| void set_filter_list(const LogFilterList &list, bool copy = true); |
| |
| inline void |
| set_fmt_timestamps() |
| { |
| m_flags |= LOG_OBJECT_FMT_TIMESTAMP; |
| } |
| |
| int log(LogAccess *lad, const char *text_entry = nullptr); |
| |
| /** Log the @a text_entry. |
| * |
| * @param lad Log accessor. |
| * @param text_entry Literal text to log. |
| * @return Result - value from Log::ReturnCodeFlags. |
| * |
| * @see Log::ReturnCodeFlags. |
| */ |
| int log(LogAccess *lad, std::string_view text_entry); |
| |
| int va_log(LogAccess *lad, const char *fmt, va_list ap); |
| |
| unsigned roll_files(long time_now = 0); |
| |
| inline int |
| add_to_flush_queue(LogBuffer *buffer) |
| { |
| int idx = m_buffer_manager_idx++ % m_flush_threads; |
| |
| m_buffer_manager[idx].add_to_flush_queue(buffer); |
| |
| return idx; |
| } |
| |
| inline size_t |
| preproc_buffers(int idx = -1) |
| { |
| size_t nfb; |
| |
| if (idx == -1) { |
| idx = m_buffer_manager_idx++ % m_flush_threads; |
| } |
| |
| nfb = m_buffer_manager[idx].preproc_buffers(m_logFile.get()); |
| |
| return nfb; |
| } |
| |
| void check_buffer_expiration(long time_now); |
| |
| void display(FILE *fd = stdout); |
| static uint64_t compute_signature(LogFormat *format, char *filename, unsigned int flags); |
| |
| inline const char * |
| get_original_filename() const |
| { |
| return m_filename; |
| } |
| inline const char * |
| get_full_filename() const |
| { |
| return (m_alt_filename ? m_alt_filename : m_filename); |
| } |
| inline const char * |
| get_base_filename() const |
| { |
| return m_basename; |
| } |
| |
| off_t get_file_size_bytes(); |
| |
| inline uint64_t |
| get_signature() const |
| { |
| return m_signature; |
| } |
| |
| inline int |
| get_rolling_interval() const |
| { |
| return m_rolling_interval_sec; |
| } |
| |
| inline void |
| set_log_file_header(const char *header) |
| { |
| m_logFile->change_header(header); |
| } |
| |
| inline void |
| set_rolling_enabled(Log::RollingEnabledValues rolling_enabled) |
| { |
| _setup_rolling(Log::config, rolling_enabled, m_rolling_interval_sec, m_rolling_offset_hr, m_rolling_size_mb); |
| } |
| |
| inline void |
| set_rolling_interval_sec(int rolling_interval_sec) |
| { |
| _setup_rolling(Log::config, m_rolling_enabled, rolling_interval_sec, m_rolling_offset_hr, m_rolling_size_mb); |
| } |
| |
| inline void |
| set_rolling_offset_hr(int rolling_offset_hr) |
| { |
| _setup_rolling(Log::config, m_rolling_enabled, m_rolling_interval_sec, rolling_offset_hr, m_rolling_size_mb); |
| } |
| |
| inline void |
| set_rolling_size_mb(int rolling_size_mb) |
| { |
| _setup_rolling(Log::config, m_rolling_enabled, m_rolling_interval_sec, m_rolling_offset_hr, rolling_size_mb); |
| } |
| |
| inline bool |
| writes_to_pipe() const |
| { |
| return (m_flags & WRITES_TO_PIPE) ? true : false; |
| } |
| inline bool |
| writes_to_disk() |
| { |
| return (m_logFile && !(m_flags & WRITES_TO_PIPE) ? true : false); |
| } |
| |
| inline unsigned int |
| get_flags() const |
| { |
| return m_flags; |
| } |
| |
| void rename(char *new_name); |
| |
| inline bool |
| has_alternate_name() const |
| { |
| return (m_alt_filename ? true : false); |
| } |
| |
| inline const char * |
| get_format_string() |
| { |
| return (m_format ? m_format->format_string() : "<none>"); |
| } |
| |
| inline void |
| force_new_buffer() |
| { |
| _checkout_write(nullptr, 0); |
| } |
| |
| bool operator==(LogObject &rhs); |
| |
| public: |
| LogFormat *m_format; |
| Ptr<LogFile> m_logFile; |
| LogFilterList m_filter_list; |
| |
| private: |
| char *m_basename; // the name of the file associated |
| // with this object, relative to |
| // the logging directory |
| char *m_filename; // the full path of the file associated |
| // with this object |
| char *m_alt_filename; // the full path of the file used |
| // instead of m_filename if the latter |
| // could not be used because of |
| // name conflicts |
| |
| unsigned int m_flags; // diverse object flags (see above) |
| uint64_t m_signature; // INK_MD5 signature for object |
| |
| Log::RollingEnabledValues m_rolling_enabled; |
| int m_flush_threads; // number of flush threads |
| int m_rolling_interval_sec; // time interval between rolls |
| // 0 means no rolling |
| int m_rolling_offset_hr; // |
| int m_rolling_size_mb; // size at which the log file rolls |
| long m_last_roll_time; // the last time this object rolled its files |
| int m_max_rolled; // maximum number of rolled logs to be kept, 0 no limit |
| int m_min_rolled; // minimum number of rolled logs to be kept, 0 no limit |
| bool m_reopen_after_rolling; // reopen log file after rolling (normally it is just renamed and closed) |
| |
| head_p m_log_buffer; // current work buffer |
| unsigned m_buffer_manager_idx; |
| LogBufferManager *m_buffer_manager; |
| |
| int m_pipe_buffer_size; |
| |
| void generate_filenames(const char *log_dir, const char *basename, LogFileFormat file_format); |
| void _setup_rolling(LogConfig *cfg, Log::RollingEnabledValues rolling_enabled, int rolling_interval_sec, int rolling_offset_hr, |
| int rolling_size_mb); |
| unsigned _roll_files(long interval_start, long interval_end); |
| |
| LogBuffer *_checkout_write(size_t *write_offset, size_t write_size); |
| |
| // noncopyable |
| LogObject(const LogObject &) = delete; |
| LogObject &operator=(const LogObject &) = delete; |
| |
| private: |
| // -- member functions not allowed -- |
| LogObject(); |
| }; |
| |
| /*------------------------------------------------------------------------- |
| TextLog |
| -------------------------------------------------------------------------*/ |
| |
| class TextLogObject : public LogObject |
| { |
| public: |
| inkcoreapi TextLogObject(const char *name, const char *log_dir, bool timestamps, const char *header, |
| Log::RollingEnabledValues rolling_enabled, int flush_threads, int rolling_interval_sec, |
| int rolling_offset_hr, int rolling_size_mb, int rolling_max_count, int rolling_min_count, |
| bool reopen_after_rolling); |
| |
| inkcoreapi int write(const char *format, ...) TS_PRINTFLIKE(2, 3); |
| inkcoreapi int va_write(const char *format, va_list ap); |
| |
| static const LogFormat *textfmt; |
| }; |
| |
| /*------------------------------------------------------------------------- |
| LogObjectManager |
| |
| A log object manager keeps track of log objects and is responsible for |
| their deletion |
| -------------------------------------------------------------------------*/ |
| |
| class LogObjectManager |
| { |
| public: |
| // error status |
| // |
| enum { |
| NO_FILENAME_CONFLICTS = 0, |
| ERROR_ACCESSING_LOG_FILE, |
| ERROR_DETERMINING_FILE_INFO, |
| CANNOT_SOLVE_FILENAME_CONFLICTS, |
| ERROR_DOING_FILESYSTEM_CHECKS |
| }; |
| |
| private: |
| typedef std::vector<LogObject *> LogObjectList; |
| |
| LogObjectList _objects; // array of configured objects |
| LogObjectList _APIobjects; // array of API objects |
| |
| public: |
| ink_mutex *_APImutex; // synchronize access to array of API objects |
| private: |
| int _manage_object(LogObject *log_object, bool is_api_object, int maxConflicts); |
| static bool _has_internal_filename_conflict(const char *filename, LogObjectList &objects); |
| int _solve_filename_conflicts(LogObject *log_obj, int maxConflicts); |
| int _solve_internal_filename_conflicts(LogObject *log_obj, int maxConflicts, int fileNum = 0); |
| void _filename_resolution_abort(const char *fname); |
| |
| public: |
| LogObjectManager(); |
| ~LogObjectManager(); |
| |
| // we don't define a destructor because the objects that the |
| // LogObjectManager manages are either passed along to another |
| // manager or moved to the list of inactive objects to be destroyed |
| |
| int |
| manage_object(LogObject *logObject, int maxConflicts = 99) |
| { |
| return _manage_object(logObject, false, maxConflicts); |
| } |
| |
| int |
| manage_api_object(LogObject *logObject, int maxConflicts = 99) |
| { |
| return _manage_object(logObject, true, maxConflicts); |
| } |
| |
| // return success |
| bool unmanage_api_object(LogObject *logObject); |
| |
| // Flush the buffers on all the managed log objects. |
| void flush_all_objects(); |
| |
| LogObject *get_object_with_signature(uint64_t signature); |
| void check_buffer_expiration(long time_now); |
| |
| unsigned roll_files(long time_now); |
| void reopen_moved_log_files(); |
| |
| int log(LogAccess *lad); |
| void display(FILE *str = stdout); |
| void add_filter_to_all(LogFilter *filter); |
| LogObject *find_by_format_name(const char *name) const; |
| size_t preproc_buffers(int idx); |
| void open_local_pipes(); |
| void transfer_objects(LogObjectManager &mgr); |
| |
| bool |
| has_api_objects() const |
| { |
| return _APIobjects.size() > 0; |
| } |
| unsigned |
| get_num_objects() const |
| { |
| return _objects.size(); |
| } |
| }; |
| |
| inline bool |
| LogObject::operator==(LogObject &old) |
| { |
| return (get_signature() == old.get_signature() && m_logFile && old.m_logFile && |
| strcmp(m_logFile->get_name(), old.m_logFile->get_name()) == 0 && (m_filter_list == old.m_filter_list) && |
| (m_rolling_interval_sec == old.m_rolling_interval_sec && m_rolling_offset_hr == old.m_rolling_offset_hr && |
| m_rolling_size_mb == old.m_rolling_size_mb && m_reopen_after_rolling == old.m_reopen_after_rolling && |
| m_max_rolled == old.m_max_rolled && m_min_rolled == old.m_min_rolled)); |
| } |
| |
| inline off_t |
| LogObject::get_file_size_bytes() |
| { |
| return m_logFile->get_size_bytes(); |
| } |