1 /** @file
2 
3   Logging
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   @verbatim
24   int Log::access (LogAccess *entry);
25 
26   The return value is Log::OK if all log objects successfully logged the
27   entry. Otherwise, it has the following bits set to indicate what happened
28 
29   ret_val & Log::SKIP      - at least one object filtered the entry
30                            - transaction logging has been disabled
31                            - the logging system is sampling and it is
32                              not yet time for a new sample
33                            - no log objects have been defined
34                            - entry to log is empty
35 
36   ret_val & Log::FAIL      an internal limit of the logging system was
37                            exceeded preventing entry from being logged
38 
39   ret_val & Log::FULL      the logging space has been exhausted
40 
41   @endverbatim
42 
43   @section example Example usage of the API
44 
45   @code
46   LogAccess entry(this);
47   int ret = Log::access(&entry);
48   @endcode
49 
50 */
51 
52 #pragma once
53 
54 #include <cstdarg>
55 #include "tscore/ink_platform.h"
56 #include "tscore/EventNotify.h"
57 #include "tscore/Regression.h"
58 #include "records/P_RecProcess.h"
59 #include "LogFile.h"
60 #include "LogBuffer.h"
61 
62 #include <unordered_map>
63 
64 class LogAccess;
65 class LogFieldList;
66 class LogFilterList;
67 class LogFormatList;
68 struct LogBufferHeader;
69 class LogFile;
70 class LogBuffer;
71 class LogFormat;
72 class LogObject;
73 class LogConfig;
74 class TextLogObject;
75 
76 class LogFlushData
77 {
78 public:
79   LINK(LogFlushData, link);
80   Ptr<LogFile> m_logfile;
81   LogBuffer *logbuffer = nullptr;
82   void *m_data;
83   int m_len;
84 
m_logfile(logfile)85   LogFlushData(LogFile *logfile, void *data, int len = -1) : m_logfile(logfile), m_data(data), m_len(len) {}
~LogFlushData()86   ~LogFlushData()
87   {
88     switch (m_logfile->m_file_format) {
89     case LOG_FILE_BINARY:
90       logbuffer = static_cast<LogBuffer *>(m_data);
91       LogBuffer::destroy(logbuffer);
92       break;
93     case LOG_FILE_ASCII:
94     case LOG_FILE_PIPE:
95       free(m_data);
96       break;
97     case N_LOGFILE_TYPES:
98     default:
99       ink_release_assert(!"Unknown file format type!");
100     }
101   }
102 };
103 
104 /**
105    This object exists to provide a namespace for the logging system.
106    It contains all data types and global variables relevant to the
107    logging system.  You can't actually create a Log object, so all
108    members are static.
109  */
110 class Log
111 {
112 public:
113   // Prevent creation of any instances of this class.
114   //
115   Log() = delete;
116 
117   enum ReturnCodeFlags {
118     LOG_OK = 1,
119     SKIP   = 2,
120     AGGR   = 4,
121     FAIL   = 8,
122     FULL   = 16,
123   };
124 
125   enum LoggingMode {
126     LOG_MODE_NONE = 0,
127     LOG_MODE_ERRORS,       // log *only* errors
128     LOG_MODE_TRANSACTIONS, // log *only* transactions
129     LOG_MODE_FULL
130   };
131 
132   enum InitFlags {
133     FIELDS_INITIALIZED = 1,
134     FULLY_INITIALIZED  = 2,
135   };
136 
137   enum ConfigFlags {
138     NO_REMOTE_MANAGEMENT = 1,
139     LOGCAT               = 4,
140   };
141 
142   enum RollingEnabledValues {
143     NO_ROLLING = 0,
144     ROLL_ON_TIME_ONLY,
145     ROLL_ON_SIZE_ONLY,
146     ROLL_ON_TIME_OR_SIZE,
147     ROLL_ON_TIME_AND_SIZE,
148     INVALID_ROLLING_VALUE
149   };
150 
151   enum {
152     MIN_ROLLING_INTERVAL_SEC = 30,   // 30 second minimum rolling interval
153     MAX_ROLLING_INTERVAL_SEC = 86400 // 24 hrs rolling interval max
154   };
155 
156   // main interface
157   static void init(int configFlags = 0);
158   static void init_fields();
159 
160   static bool
transaction_logging_enabled()161   transaction_logging_enabled()
162   {
163     return (logging_mode == LOG_MODE_FULL || logging_mode == LOG_MODE_TRANSACTIONS);
164   }
165 
166   static bool
error_logging_enabled()167   error_logging_enabled()
168   {
169     return (logging_mode == LOG_MODE_FULL || logging_mode == LOG_MODE_ERRORS);
170   }
171 
172   static int access(LogAccess *lad);
173   static int va_error(const char *format, va_list ap);
174   static int error(const char *format, ...) TS_PRINTFLIKE(1, 2);
175 
176   /////////////////////////////////////////////////////////////////////////
177   // 'Wire tracing' enabled by source ip or by percentage of connections //
178   /////////////////////////////////////////////////////////////////////////
179   static void trace_in(const sockaddr *peer_addr, uint16_t peer_port, const char *format_string, ...) TS_PRINTFLIKE(3, 4);
180   static void trace_out(const sockaddr *peer_addr, uint16_t peer_port, const char *format_string, ...) TS_PRINTFLIKE(3, 4);
181   static void trace_va(bool in, const sockaddr *peer_addr, uint16_t peer_port, const char *format_string, va_list ap);
182 
183   // public data members
184   static LogObject *error_log;
185   /** The latest fully initialized LogConfig.
186    *
187    * This is the safe, fully initialed LogConfig object to query against when
188    * performing logging operations.
189    */
190   static LogConfig *config;
191   static LogFieldList global_field_list;
192   static std::unordered_map<std::string, LogField *> field_symbol_hash;
193   static LoggingMode logging_mode;
194 
195   // logging thread stuff
196   static EventNotify *preproc_notify;
197   static void *preproc_thread_main(void *args);
198   static EventNotify *flush_notify;
199   static InkAtomicList *flush_data_list;
200   static void *flush_thread_main(void *args);
201 
202   static int preproc_threads;
203 
204   // reconfiguration stuff
205   static void change_configuration();
206 
207   static int handle_logging_mode_change(const char *name, RecDataT data_type, RecData data, void *cookie);
208   static int handle_periodic_tasks_int_change(const char *name, RecDataT data_type, RecData data, void *cookie);
209 
210   /** Check each log file path to see whether it exists and re-open if not.
211    *
212    * This is called when an external log rotation entity has moved log files to
213    * rolled names. This checks whether the original log file exists and, if
214    * not, closes the file descriptor and re-opens the file.
215    */
216   static int handle_log_rotation_request();
217 
218   friend void RegressionTest_LogObjectManager_Transfer(RegressionTest *, int, int *);
219 
220 private:
221   static void periodic_tasks(long time_now);
222   static void create_threads();
223   static void init_when_enabled();
224 
225   static int init_status;
226   static int config_flags;
227   static bool logging_mode_changed;
228   static bool log_rotate_signal_received;
229   static uint32_t periodic_tasks_interval;
230 };
231 
232 static inline bool
LogRollingEnabledIsValid(int enabled)233 LogRollingEnabledIsValid(int enabled)
234 {
235   return (enabled >= Log::NO_ROLLING || enabled < Log::INVALID_ROLLING_VALUE);
236 }
237 
238 #define TraceIn(flag, ...)        \
239   do {                            \
240     if (unlikely(flag))           \
241       Log::trace_in(__VA_ARGS__); \
242   } while (0)
243 
244 #define TraceOut(flag, ...)        \
245   do {                             \
246     if (unlikely(flag))            \
247       Log::trace_out(__VA_ARGS__); \
248   } while (0)
249