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 /***************************************************************************
25 Log.cc
26
27 This file defines the implementation of the static Log class, which is
28 primarily used as a namespace. That is, there are no Log objects, but the
29 class scope and static members provide a protected namespace for all of
30 the logging routines and enumerated types. When C++ namespaces are more
31 widely-implemented, Log could be implemented as a namespace rather than a
32 class.
33
34 ***************************************************************************/
35 #include "tscore/ink_platform.h"
36 #include "tscore/TSSystemState.h"
37 #include "P_EventSystem.h"
38 #include "P_Net.h"
39 #include "I_Machine.h"
40 #include "HTTP.h"
41
42 #include "LogAccess.h"
43 #include "LogField.h"
44 #include "LogFilter.h"
45 #include "LogFormat.h"
46 #include "LogFile.h"
47 #include "LogObject.h"
48 #include "LogConfig.h"
49 #include "LogBuffer.h"
50 #include "LogUtils.h"
51 #include "Log.h"
52 #include "tscore/SimpleTokenizer.h"
53
54 #include "tscore/ink_apidefs.h"
55
56 #define PERIODIC_TASKS_INTERVAL_FALLBACK 5
57
58 // Log global objects
59 inkcoreapi LogObject *Log::error_log = nullptr;
60 LogFieldList Log::global_field_list;
61 Log::LoggingMode Log::logging_mode = LOG_MODE_NONE;
62
63 // Flush thread stuff
64 EventNotify *Log::preproc_notify;
65 EventNotify *Log::flush_notify;
66 InkAtomicList *Log::flush_data_list;
67
68 // Log private objects
69 int Log::preproc_threads;
70 int Log::init_status = 0;
71 int Log::config_flags = 0;
72 bool Log::logging_mode_changed = false;
73 bool Log::log_rotate_signal_received = false;
74 uint32_t Log::periodic_tasks_interval = PERIODIC_TASKS_INTERVAL_FALLBACK;
75
76 // Hash table for LogField symbols
77 std::unordered_map<std::string, LogField *> Log::field_symbol_hash;
78
79 RecRawStatBlock *log_rsb;
80
81 /*-------------------------------------------------------------------------
82 Log::change_configuration
83
84 This routine is invoked when the current LogConfig object says it needs
85 to be changed (as the result of a manager callback).
86 -------------------------------------------------------------------------*/
87
88 LogConfig *Log::config = nullptr;
89 static unsigned log_configid = 0;
90
91 // Downcast from a Ptr<LogFieldAliasTable> to a Ptr<LogFieldAliasMap>.
92 static Ptr<LogFieldAliasMap>
make_alias_map(Ptr<LogFieldAliasTable> & table)93 make_alias_map(Ptr<LogFieldAliasTable> &table)
94 {
95 return make_ptr(static_cast<LogFieldAliasMap *>(table.get()));
96 }
97
98 void
change_configuration()99 Log::change_configuration()
100 {
101 LogConfig *prev_config = Log::config;
102 LogConfig *new_config = nullptr;
103
104 Debug("log-config", "Changing configuration ...");
105
106 new_config = new LogConfig;
107 ink_assert(new_config != nullptr);
108 new_config->read_configuration_variables();
109
110 // grab the _APImutex so we can transfer the api objects to
111 // the new config
112 //
113 ink_mutex_acquire(prev_config->log_object_manager._APImutex);
114 Debug("log-api-mutex", "Log::change_configuration acquired api mutex");
115
116 new_config->init(prev_config);
117
118 // Make the new LogConfig active.
119 ink_atomic_swap(&Log::config, new_config);
120
121 // XXX There is a race condition with API objects. If TSTextLogObjectCreate()
122 // is called before the Log::config swap, then it will be blocked on the lock
123 // on the *old* LogConfig and register it's LogObject with that manager. If
124 // this happens, then the new TextLogObject will be immediately lost. Traffic
125 // Server would crash the next time the plugin referenced the freed object.
126
127 ink_mutex_release(prev_config->log_object_manager._APImutex);
128 Debug("log-api-mutex", "Log::change_configuration released api mutex");
129
130 // Register the new config in the config processor; the old one will now be scheduled for a
131 // future deletion. We don't need to do anything magical with refcounts, since the
132 // configProcessor will keep a reference count, and drop it when the deletion is scheduled.
133 configProcessor.set(log_configid, new_config);
134
135 // If we replaced the logging configuration, flush any log
136 // objects that weren't transferred to the new config ...
137 prev_config->log_object_manager.flush_all_objects();
138
139 Debug("log-config", "... new configuration in place");
140 }
141
142 /*-------------------------------------------------------------------------
143 PERIODIC EVENTS
144
145 There are a number of things that need to get done on a periodic basis,
146 such as checking the amount of space used, seeing if it's time to roll
147 files, and flushing idle log buffers. Most of these tasks require having
148 exclusive access to the back-end structures, which is controlled by the
149 flush_thread. Therefore, we will simply instruct the flush thread to
150 execute a periodic_tasks() function once per period. To ensure that the
151 tasks are executed AT LEAST once each period, we'll register a call-back
152 with the system and trigger the flush thread's condition variable. To
153 ensure that the tasks are executed AT MOST once per period, the flush
154 thread will keep track of executions per period.
155 -------------------------------------------------------------------------*/
156
157 /*-------------------------------------------------------------------------
158 PeriodicWakeup
159
160 This continuation is invoked each second to wake-up the flush thread,
161 just in case it's sleeping on the job.
162 -------------------------------------------------------------------------*/
163
164 struct PeriodicWakeup;
165 using PeriodicWakeupHandler = int (PeriodicWakeup::*)(int, void *);
166 struct PeriodicWakeup : Continuation {
167 int m_preproc_threads;
168 int m_flush_threads;
169
170 int
wakeupPeriodicWakeup171 wakeup(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
172 {
173 for (int i = 0; i < m_preproc_threads; i++) {
174 Log::preproc_notify[i].signal();
175 }
176 for (int i = 0; i < m_flush_threads; i++) {
177 Log::flush_notify[i].signal();
178 }
179 return EVENT_CONT;
180 }
181
PeriodicWakeupPeriodicWakeup182 PeriodicWakeup(int preproc_threads, int flush_threads)
183 : Continuation(new_ProxyMutex()), m_preproc_threads(preproc_threads), m_flush_threads(flush_threads)
184 {
185 SET_HANDLER((PeriodicWakeupHandler)&PeriodicWakeup::wakeup);
186 }
187 };
188
189 /*-------------------------------------------------------------------------
190 Log::periodic_tasks
191
192 This function contains all of the tasks that need to be done each
193 PERIODIC_TASKS_INTERVAL seconds.
194 -------------------------------------------------------------------------*/
195
196 void
periodic_tasks(long time_now)197 Log::periodic_tasks(long time_now)
198 {
199 Debug("log-api-mutex", "entering Log::periodic_tasks");
200
201 if (logging_mode_changed || Log::config->reconfiguration_needed) {
202 Debug("log-config", "Performing reconfiguration, init status = %d", init_status);
203
204 if (logging_mode_changed) {
205 int val = static_cast<int>(REC_ConfigReadInteger("proxy.config.log.logging_enabled"));
206
207 if (val < LOG_MODE_NONE || val > LOG_MODE_FULL) {
208 logging_mode = LOG_MODE_FULL;
209 Warning("proxy.config.log.logging_enabled has an invalid "
210 "value setting it to %d",
211 logging_mode);
212 } else {
213 logging_mode = static_cast<LoggingMode>(val);
214 }
215 logging_mode_changed = false;
216 }
217 // even if we are disabling logging, we call change configuration
218 // so that log objects are flushed
219 //
220 change_configuration();
221 } else if (logging_mode > LOG_MODE_NONE || config->has_api_objects()) {
222 Debug("log-periodic", "Performing periodic tasks");
223 Debug("log-periodic", "Periodic task interval = %d", periodic_tasks_interval);
224
225 // Check if space is ok and update the space used
226 //
227 if (config->space_is_short() || time_now % config->space_used_frequency == 0) {
228 Log::config->update_space_used();
229 }
230
231 // See if there are any buffers that have expired
232 //
233 Log::config->log_object_manager.check_buffer_expiration(time_now);
234
235 // Check if we received a request to roll, and roll if so, otherwise
236 // give objects a chance to roll if they need to
237 //
238 if (Log::config->roll_log_files_now) {
239 if (error_log) {
240 error_log->roll_files(time_now);
241 }
242 Log::config->log_object_manager.roll_files(time_now);
243 Log::config->roll_log_files_now = false;
244 } else {
245 if (error_log) {
246 error_log->roll_files(time_now);
247 }
248 Log::config->log_object_manager.roll_files(time_now);
249 }
250 if (log_rotate_signal_received) {
251 Log::config->log_object_manager.reopen_moved_log_files();
252 log_rotate_signal_received = false;
253 }
254 }
255 }
256
257 /*-------------------------------------------------------------------------
258 MAIN INTERFACE
259 -------------------------------------------------------------------------*/
260 struct LoggingPreprocContinuation : public Continuation {
261 int m_idx;
262
263 int
mainEventLoggingPreprocContinuation264 mainEvent(int /* event ATS_UNUSED */, void * /* data ATS_UNUSED */)
265 {
266 Log::preproc_thread_main((void *)&m_idx);
267 return 0;
268 }
269
LoggingPreprocContinuationLoggingPreprocContinuation270 explicit LoggingPreprocContinuation(int idx) : Continuation(nullptr), m_idx(idx)
271 {
272 SET_HANDLER(&LoggingPreprocContinuation::mainEvent);
273 }
274 };
275
276 struct LoggingFlushContinuation : public Continuation {
277 int m_idx;
278
279 int
mainEventLoggingFlushContinuation280 mainEvent(int /* event ATS_UNUSED */, void * /* data ATS_UNUSED */)
281 {
282 Log::flush_thread_main((void *)&m_idx);
283 return 0;
284 }
285
LoggingFlushContinuationLoggingFlushContinuation286 explicit LoggingFlushContinuation(int idx) : Continuation(nullptr), m_idx(idx)
287 {
288 SET_HANDLER(&LoggingFlushContinuation::mainEvent);
289 }
290 };
291
292 /*-------------------------------------------------------------------------
293 Log::init_fields
294
295 Define the available logging fields.
296 This used to be part of the init() function, but now is separate so that
297 standalone programs that do not require more services (e.g., that do not
298 need to read records.config) can just call init_fields.
299
300 Note that the LogFields are added to the list with the copy flag false so
301 that the LogFieldList destructor will reclaim this memory.
302 -------------------------------------------------------------------------*/
303 void
init_fields()304 Log::init_fields()
305 {
306 if (init_status & FIELDS_INITIALIZED) {
307 return;
308 }
309
310 LogField *field;
311
312 //
313 // Initializes material to find a milestone name from their
314 // name in a rapid manner.
315 LogField::init_milestone_container();
316
317 // client -> proxy fields
318 field = new LogField("client_host_ip", "chi", LogField::IP, &LogAccess::marshal_client_host_ip, &LogAccess::unmarshal_ip_to_str);
319 global_field_list.add(field, false);
320 field_symbol_hash.emplace("chi", field);
321
322 field =
323 new LogField("client_host_port", "chp", LogField::sINT, &LogAccess::marshal_client_host_port, &LogAccess::unmarshal_int_to_str);
324 global_field_list.add(field, false);
325 field_symbol_hash.emplace("chp", field);
326
327 field =
328 new LogField("client_host_ip_hex", "chih", LogField::IP, &LogAccess::marshal_client_host_ip, &LogAccess::unmarshal_ip_to_hex);
329 global_field_list.add(field, false);
330 field_symbol_hash.emplace("chih", field);
331
332 // interface ip
333
334 field =
335 new LogField("host_interface_ip", "hii", LogField::IP, &LogAccess::marshal_host_interface_ip, &LogAccess::unmarshal_ip_to_str);
336 global_field_list.add(field, false);
337 field_symbol_hash.emplace("hii", field);
338
339 field = new LogField("host_interface_ip_hex", "hiih", LogField::IP, &LogAccess::marshal_host_interface_ip,
340 &LogAccess::unmarshal_ip_to_hex);
341 global_field_list.add(field, false);
342 field_symbol_hash.emplace("hiih", field);
343 // interface ip end
344 field = new LogField("client_auth_user_name", "caun", LogField::STRING, &LogAccess::marshal_client_auth_user_name,
345 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
346 global_field_list.add(field, false);
347 field_symbol_hash.emplace("caun", field);
348
349 field = new LogField("plugin_identity_id", "piid", LogField::sINT, &LogAccess::marshal_plugin_identity_id,
350 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_int_to_str));
351 global_field_list.add(field, false);
352 field_symbol_hash.emplace("piid", field);
353
354 field = new LogField("plugin_identity_tag", "pitag", LogField::STRING, &LogAccess::marshal_plugin_identity_tag,
355 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
356 global_field_list.add(field, false);
357 field_symbol_hash.emplace("pitag", field);
358
359 field = new LogField("client_req_timestamp_sec", "cqts", LogField::sINT, &LogAccess::marshal_client_req_timestamp_sec,
360 &LogAccess::unmarshal_int_to_str);
361 global_field_list.add(field, false);
362 field_symbol_hash.emplace("cqts", field);
363
364 field = new LogField("client_req_timestamp_hex_sec", "cqth", LogField::sINT, &LogAccess::marshal_client_req_timestamp_sec,
365 &LogAccess::unmarshal_int_to_str_hex);
366 global_field_list.add(field, false);
367 field_symbol_hash.emplace("cqth", field);
368
369 field = new LogField("client_req_timestamp_squid", "cqtq", LogField::sINT, &LogAccess::marshal_client_req_timestamp_ms,
370 &LogAccess::unmarshal_ttmsf);
371 global_field_list.add(field, false);
372 field_symbol_hash.emplace("cqtq", field);
373
374 field = new LogField("client_req_timestamp_netscape", "cqtn", LogField::sINT, &LogAccess::marshal_client_req_timestamp_sec,
375 &LogAccess::unmarshal_int_to_netscape_str);
376 global_field_list.add(field, false);
377 field_symbol_hash.emplace("cqtn", field);
378
379 field = new LogField("client_req_timestamp_date", "cqtd", LogField::sINT, &LogAccess::marshal_client_req_timestamp_sec,
380 &LogAccess::unmarshal_int_to_date_str);
381 global_field_list.add(field, false);
382 field_symbol_hash.emplace("cqtd", field);
383
384 field = new LogField("client_req_timestamp_time", "cqtt", LogField::sINT, &LogAccess::marshal_client_req_timestamp_sec,
385 &LogAccess::unmarshal_int_to_time_str);
386 global_field_list.add(field, false);
387 field_symbol_hash.emplace("cqtt", field);
388
389 field = new LogField("client_req_text", "cqtx", LogField::STRING, &LogAccess::marshal_client_req_text,
390 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_http_text));
391 global_field_list.add(field, false);
392 field_symbol_hash.emplace("cqtx", field);
393
394 field = new LogField("client_req_http_method", "cqhm", LogField::STRING, &LogAccess::marshal_client_req_http_method,
395 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
396 global_field_list.add(field, false);
397 field_symbol_hash.emplace("cqhm", field);
398
399 field = new LogField("client_req_url", "cqu", LogField::STRING, &LogAccess::marshal_client_req_url,
400 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str), &LogAccess::set_client_req_url);
401 global_field_list.add(field, false);
402 field_symbol_hash.emplace("cqu", field);
403
404 field = new LogField("client_req_url_canonical", "cquc", LogField::STRING, &LogAccess::marshal_client_req_url_canon,
405 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str), &LogAccess::set_client_req_url_canon);
406 global_field_list.add(field, false);
407 field_symbol_hash.emplace("cquc", field);
408
409 field = new LogField(
410 "client_req_unmapped_url_canonical", "cquuc", LogField::STRING, &LogAccess::marshal_client_req_unmapped_url_canon,
411 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str), &LogAccess::set_client_req_unmapped_url_canon);
412 global_field_list.add(field, false);
413 field_symbol_hash.emplace("cquuc", field);
414
415 field = new LogField("client_req_unmapped_url_path", "cquup", LogField::STRING, &LogAccess::marshal_client_req_unmapped_url_path,
416 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str),
417 &LogAccess::set_client_req_unmapped_url_path);
418 global_field_list.add(field, false);
419 field_symbol_hash.emplace("cquup", field);
420
421 field = new LogField("client_req_unmapped_url_host", "cquuh", LogField::STRING, &LogAccess::marshal_client_req_unmapped_url_host,
422 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str),
423 &LogAccess::set_client_req_unmapped_url_host);
424 global_field_list.add(field, false);
425 field_symbol_hash.emplace("cquuh", field);
426
427 field = new LogField("client_req_url_scheme", "cqus", LogField::STRING, &LogAccess::marshal_client_req_url_scheme,
428 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
429 global_field_list.add(field, false);
430 field_symbol_hash.emplace("cqus", field);
431
432 field = new LogField("client_req_url_path", "cqup", LogField::STRING, &LogAccess::marshal_client_req_url_path,
433 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str), &LogAccess::set_client_req_url_path);
434 global_field_list.add(field, false);
435 field_symbol_hash.emplace("cqup", field);
436
437 field = new LogField("client_req_http_version", "cqhv", LogField::dINT, &LogAccess::marshal_client_req_http_version,
438 &LogAccess::unmarshal_http_version);
439 global_field_list.add(field, false);
440 field_symbol_hash.emplace("cqhv", field);
441
442 field = new LogField("client_req_protocol_version", "cqpv", LogField::dINT, &LogAccess::marshal_client_req_protocol_version,
443 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
444 global_field_list.add(field, false);
445 field_symbol_hash.emplace("cqpv", field);
446
447 field = new LogField("server_req_protocol_version", "sqpv", LogField::dINT, &LogAccess::marshal_server_req_protocol_version,
448 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
449 global_field_list.add(field, false);
450 field_symbol_hash.emplace("sqpv", field);
451
452 field = new LogField("client_req_header_len", "cqhl", LogField::sINT, &LogAccess::marshal_client_req_header_len,
453 &LogAccess::unmarshal_int_to_str);
454 global_field_list.add(field, false);
455 field_symbol_hash.emplace("cqhl", field);
456
457 field = new LogField("client_req_squid_len", "cqql", LogField::sINT, &LogAccess::marshal_client_req_squid_len,
458 &LogAccess::unmarshal_int_to_str);
459 global_field_list.add(field, false);
460 field_symbol_hash.emplace("cqql", field);
461
462 field = new LogField("cache_lookup_url_canonical", "cluc", LogField::STRING, &LogAccess::marshal_cache_lookup_url_canon,
463 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
464 global_field_list.add(field, false);
465 field_symbol_hash.emplace("cluc", field);
466
467 field = new LogField("client_sni_server_name", "cssn", LogField::STRING, &LogAccess::marshal_client_sni_server_name,
468 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
469 global_field_list.add(field, false);
470 field_symbol_hash.emplace("cssn", field);
471
472 field = new LogField("client_ssl_cert_provided", "cscert", LogField::STRING, &LogAccess::marshal_client_provided_cert,
473 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_int_to_str));
474 global_field_list.add(field, false);
475 field_symbol_hash.emplace("cscert", field);
476
477 field = new LogField("proxy_ssl_cert_provided", "pscert", LogField::STRING, &LogAccess::marshal_proxy_provided_cert,
478 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_int_to_str));
479 global_field_list.add(field, false);
480 field_symbol_hash.emplace("pscert", field);
481
482 field = new LogField("process_uuid", "puuid", LogField::STRING, &LogAccess::marshal_process_uuid,
483 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
484 global_field_list.add(field, false);
485 field_symbol_hash.emplace("puuid", field);
486
487 field = new LogField("client_req_content_len", "cqcl", LogField::sINT, &LogAccess::marshal_client_req_content_len,
488 &LogAccess::unmarshal_int_to_str);
489 global_field_list.add(field, false);
490 field_symbol_hash.emplace("cqcl", field);
491
492 field = new LogField("client_req_tcp_reused", "cqtr", LogField::dINT, &LogAccess::marshal_client_req_tcp_reused,
493 &LogAccess::unmarshal_int_to_str);
494 global_field_list.add(field, false);
495 field_symbol_hash.emplace("cqtr", field);
496
497 field = new LogField("client_req_is_ssl", "cqssl", LogField::dINT, &LogAccess::marshal_client_req_is_ssl,
498 &LogAccess::unmarshal_int_to_str);
499 global_field_list.add(field, false);
500 field_symbol_hash.emplace("cqssl", field);
501
502 field = new LogField("client_req_ssl_reused", "cqssr", LogField::dINT, &LogAccess::marshal_client_req_ssl_reused,
503 &LogAccess::unmarshal_int_to_str);
504 global_field_list.add(field, false);
505 field_symbol_hash.emplace("cqssr", field);
506
507 field = new LogField("client_req_is_internal", "cqint", LogField::sINT, &LogAccess::marshal_client_req_is_internal,
508 &LogAccess::unmarshal_int_to_str);
509 global_field_list.add(field, false);
510 field_symbol_hash.emplace("cqint", field);
511
512 field = new LogField("client_req_mptcp", "cqmpt", LogField::sINT, &LogAccess::marshal_client_req_mptcp_state,
513 &LogAccess::unmarshal_int_to_str);
514 global_field_list.add(field, false);
515 field_symbol_hash.emplace("cqmpt", field);
516
517 field = new LogField("client_sec_protocol", "cqssv", LogField::STRING, &LogAccess::marshal_client_security_protocol,
518 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
519 global_field_list.add(field, false);
520 field_symbol_hash.emplace("cqssv", field);
521
522 field = new LogField("client_cipher_suite", "cqssc", LogField::STRING, &LogAccess::marshal_client_security_cipher_suite,
523 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
524 global_field_list.add(field, false);
525 field_symbol_hash.emplace("cqssc", field);
526
527 field = new LogField("client_curve", "cqssu", LogField::STRING, &LogAccess::marshal_client_security_curve,
528 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
529 global_field_list.add(field, false);
530 field_symbol_hash.emplace("cqssu", field);
531
532 field = new LogField("client_sec_alpn", "cqssa", LogField::STRING, &LogAccess::marshal_client_security_alpn,
533 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
534 global_field_list.add(field, false);
535 field_symbol_hash.emplace("cqssa", field);
536
537 Ptr<LogFieldAliasTable> finish_status_map = make_ptr(new LogFieldAliasTable);
538 finish_status_map->init(N_LOG_FINISH_CODE_TYPES, LOG_FINISH_FIN, "FIN", LOG_FINISH_INTR, "INTR", LOG_FINISH_TIMEOUT, "TIMEOUT");
539
540 field = new LogField("client_finish_status_code", "cfsc", LogField::sINT, &LogAccess::marshal_client_finish_status_code,
541 &LogAccess::unmarshal_finish_status, make_alias_map(finish_status_map));
542 global_field_list.add(field, false);
543 field_symbol_hash.emplace("cfsc", field);
544
545 field =
546 new LogField("client_req_id", "crid", LogField::sINT, &LogAccess::marshal_client_req_id, &LogAccess::unmarshal_int_to_str);
547 global_field_list.add(field, false);
548 field_symbol_hash.emplace("crid", field);
549
550 field = new LogField("client_req_uuid", "cruuid", LogField::STRING, &LogAccess::marshal_client_req_uuid,
551 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
552 global_field_list.add(field, false);
553 field_symbol_hash.emplace("cruuid", field);
554
555 field = new LogField("client_rx_error_code", "crec", LogField::STRING, &LogAccess::marshal_client_rx_error_code,
556 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
557 global_field_list.add(field, false);
558 field_symbol_hash.emplace("crec", field);
559
560 field = new LogField("client_tx_error_code", "ctec", LogField::STRING, &LogAccess::marshal_client_tx_error_code,
561 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
562 global_field_list.add(field, false);
563 field_symbol_hash.emplace("ctec", field);
564
565 field = new LogField("client_request_all_header_fields", "cqah", LogField::STRING,
566 &LogAccess::marshal_client_req_all_header_fields, &LogUtils::unmarshalMimeHdr);
567 global_field_list.add(field, false);
568 field_symbol_hash.emplace("cqah", field);
569
570 // proxy -> client fields
571 field = new LogField("proxy_resp_content_type", "psct", LogField::STRING, &LogAccess::marshal_proxy_resp_content_type,
572 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
573 global_field_list.add(field, false);
574 field_symbol_hash.emplace("psct", field);
575
576 field = new LogField("proxy_resp_reason_phrase", "prrp", LogField::STRING, &LogAccess::marshal_proxy_resp_reason_phrase,
577 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
578 global_field_list.add(field, false);
579 field_symbol_hash.emplace("prrp", field);
580
581 field = new LogField("proxy_resp_squid_len", "psql", LogField::sINT, &LogAccess::marshal_proxy_resp_squid_len,
582 &LogAccess::unmarshal_int_to_str);
583 global_field_list.add(field, false);
584 field_symbol_hash.emplace("psql", field);
585
586 field = new LogField("proxy_resp_content_len", "pscl", LogField::sINT, &LogAccess::marshal_proxy_resp_content_len,
587 &LogAccess::unmarshal_int_to_str);
588 global_field_list.add(field, false);
589 field_symbol_hash.emplace("pscl", field);
590
591 field = new LogField("proxy_resp_content_len_hex", "psch", LogField::sINT, &LogAccess::marshal_proxy_resp_content_len,
592 &LogAccess::unmarshal_int_to_str_hex);
593 global_field_list.add(field, false);
594 field_symbol_hash.emplace("psch", field);
595
596 field = new LogField("proxy_resp_status_code", "pssc", LogField::sINT, &LogAccess::marshal_proxy_resp_status_code,
597 &LogAccess::unmarshal_http_status);
598 global_field_list.add(field, false);
599 field_symbol_hash.emplace("pssc", field);
600
601 field = new LogField("proxy_resp_header_len", "pshl", LogField::sINT, &LogAccess::marshal_proxy_resp_header_len,
602 &LogAccess::unmarshal_int_to_str);
603 global_field_list.add(field, false);
604 field_symbol_hash.emplace("pshl", field);
605
606 field = new LogField("proxy_finish_status_code", "pfsc", LogField::sINT, &LogAccess::marshal_proxy_finish_status_code,
607 &LogAccess::unmarshal_finish_status, make_alias_map(finish_status_map));
608 global_field_list.add(field, false);
609 field_symbol_hash.emplace("pfsc", field);
610
611 Ptr<LogFieldAliasTable> cache_code_map = make_ptr(new LogFieldAliasTable);
612 cache_code_map->init(
613 52, SQUID_LOG_EMPTY, "UNDEFINED", SQUID_LOG_TCP_HIT, "TCP_HIT", SQUID_LOG_TCP_DISK_HIT, "TCP_DISK_HIT", SQUID_LOG_TCP_MEM_HIT,
614 "TCP_MEM_HIT", SQUID_LOG_TCP_MISS, "TCP_MISS", SQUID_LOG_TCP_EXPIRED_MISS, "TCP_EXPIRED_MISS", SQUID_LOG_TCP_REFRESH_HIT,
615 "TCP_REFRESH_HIT", SQUID_LOG_TCP_REF_FAIL_HIT, "TCP_REFRESH_FAIL_HIT", SQUID_LOG_TCP_REFRESH_MISS, "TCP_REFRESH_MISS",
616 SQUID_LOG_TCP_CLIENT_REFRESH, "TCP_CLIENT_REFRESH_MISS", SQUID_LOG_TCP_IMS_HIT, "TCP_IMS_HIT", SQUID_LOG_TCP_IMS_MISS,
617 "TCP_IMS_MISS", SQUID_LOG_TCP_SWAPFAIL, "TCP_SWAPFAIL_MISS", SQUID_LOG_TCP_DENIED, "TCP_DENIED", SQUID_LOG_TCP_WEBFETCH_MISS,
618 "TCP_WEBFETCH_MISS", SQUID_LOG_TCP_FUTURE_2, "TCP_FUTURE_2", SQUID_LOG_TCP_HIT_REDIRECT, "TCP_HIT_REDIRECT",
619 SQUID_LOG_TCP_MISS_REDIRECT, "TCP_MISS_REDIRECT", SQUID_LOG_TCP_HIT_X_REDIRECT, "TCP_HIT_X_REDIRECT",
620 SQUID_LOG_TCP_MISS_X_REDIRECT, "TCP_MISS_X_REDIRECT", SQUID_LOG_UDP_HIT, "UDP_HIT", SQUID_LOG_UDP_WEAK_HIT, "UDP_WEAK_HIT",
621 SQUID_LOG_UDP_HIT_OBJ, "UDP_HIT_OBJ", SQUID_LOG_UDP_MISS, "UDP_MISS", SQUID_LOG_UDP_DENIED, "UDP_DENIED", SQUID_LOG_UDP_INVALID,
622 "UDP_INVALID", SQUID_LOG_UDP_RELOADING, "UDP_RELOADING", SQUID_LOG_UDP_FUTURE_1, "UDP_FUTURE_1", SQUID_LOG_UDP_FUTURE_2,
623 "UDP_FUTURE_2", SQUID_LOG_ERR_READ_TIMEOUT, "ERR_READ_TIMEOUT", SQUID_LOG_ERR_LIFETIME_EXP, "ERR_LIFETIME_EXP",
624 SQUID_LOG_ERR_POST_ENTITY_TOO_LARGE, "ERR_POST_ENTITY_TOO_LARGE", SQUID_LOG_ERR_NO_CLIENTS_BIG_OBJ, "ERR_NO_CLIENTS_BIG_OBJ",
625 SQUID_LOG_ERR_READ_ERROR, "ERR_READ_ERROR", SQUID_LOG_ERR_CLIENT_ABORT, "ERR_CLIENT_ABORT", SQUID_LOG_ERR_CLIENT_READ_ERROR,
626 "ERR_CLIENT_READ_ERROR", SQUID_LOG_ERR_CONNECT_FAIL, "ERR_CONNECT_FAIL", SQUID_LOG_ERR_INVALID_REQ, "ERR_INVALID_REQ",
627 SQUID_LOG_ERR_UNSUP_REQ, "ERR_UNSUP_REQ", SQUID_LOG_ERR_INVALID_URL, "ERR_INVALID_URL", SQUID_LOG_ERR_NO_FDS, "ERR_NO_FDS",
628 SQUID_LOG_ERR_DNS_FAIL, "ERR_DNS_FAIL", SQUID_LOG_ERR_NOT_IMPLEMENTED, "ERR_NOT_IMPLEMENTED", SQUID_LOG_ERR_CANNOT_FETCH,
629 "ERR_CANNOT_FETCH", SQUID_LOG_ERR_NO_RELAY, "ERR_NO_RELAY", SQUID_LOG_ERR_DISK_IO, "ERR_DISK_IO",
630 SQUID_LOG_ERR_ZERO_SIZE_OBJECT, "ERR_ZERO_SIZE_OBJECT", SQUID_LOG_ERR_PROXY_DENIED, "ERR_PROXY_DENIED",
631 SQUID_LOG_ERR_WEBFETCH_DETECTED, "ERR_WEBFETCH_DETECTED", SQUID_LOG_ERR_FUTURE_1, "ERR_FUTURE_1", SQUID_LOG_ERR_LOOP_DETECTED,
632 "ERR_LOOP_DETECTED", SQUID_LOG_ERR_UNKNOWN, "ERR_UNKNOWN");
633
634 Ptr<LogFieldAliasTable> cache_subcode_map = make_ptr(new LogFieldAliasTable);
635 cache_subcode_map->init(2, SQUID_SUBCODE_EMPTY, "NONE", SQUID_SUBCODE_NUM_REDIRECTIONS_EXCEEDED, "NUM_REDIRECTIONS_EXCEEDED");
636
637 Ptr<LogFieldAliasTable> cache_hit_miss_map = make_ptr(new LogFieldAliasTable);
638 cache_hit_miss_map->init(21, SQUID_HIT_RESERVED, "HIT", SQUID_HIT_LEVEL_1, "HIT_RAM", // Also SQUID_HIT_RAM
639 SQUID_HIT_LEVEL_2, "HIT_SSD", // Also SQUID_HIT_SSD
640 SQUID_HIT_LEVEL_3, "HIT_DISK", // Also SQUID_HIT_DISK
641 SQUID_HIT_LEVEL_4, "HIT_CLUSTER", // Also SQUID_HIT_CLUSTER
642 SQUID_HIT_LEVEL_5, "HIT_NET", // Also SQUID_HIT_NET
643 SQUID_HIT_LEVEL_6, "HIT_LEVEL_6", SQUID_HIT_LEVEL_7, "HIT_LEVEL_7", SQUID_HIT_LEVEL_8, "HIT_LEVEL_8",
644 SQUID_HIT_LEVEl_9, "HIT_LEVEL_9", SQUID_MISS_NONE, "MISS", SQUID_MISS_HTTP_NON_CACHE,
645 "MISS_HTTP_NON_CACHE", SQUID_MISS_HTTP_NO_DLE, "MISS_HTTP_NO_DLE", SQUID_MISS_HTTP_NO_LE,
646 "MISS_HTTP_NO_LE", SQUID_MISS_HTTP_CONTENT, "MISS_HTTP_CONTENT", SQUID_MISS_PRAGMA_NOCACHE,
647 "MISS_PRAGMA_NOCACHE", SQUID_MISS_PASS, "MISS_PASS", SQUID_MISS_PRE_EXPIRED, "MISS_PRE_EXPIRED",
648 SQUID_MISS_ERROR, "MISS_ERROR", SQUID_MISS_CACHE_BYPASS, "MISS_CACHE_BYPASS",
649 SQUID_HIT_MISS_INVALID_ASSIGNED_CODE, "INVALID_CODE");
650
651 field = new LogField("cache_result_code", "crc", LogField::sINT, &LogAccess::marshal_cache_result_code,
652 &LogAccess::unmarshal_cache_code, make_alias_map(cache_code_map));
653 global_field_list.add(field, false);
654 field_symbol_hash.emplace("crc", field);
655
656 // Reuse the unmarshalling code from crc
657 field = new LogField("cache_result_subcode", "crsc", LogField::sINT, &LogAccess::marshal_cache_result_subcode,
658 &LogAccess::unmarshal_cache_code, make_alias_map(cache_subcode_map));
659 global_field_list.add(field, false);
660 field_symbol_hash.emplace("crsc", field);
661
662 field = new LogField("cache_hit_miss", "chm", LogField::sINT, &LogAccess::marshal_cache_hit_miss,
663 &LogAccess::unmarshal_cache_hit_miss, make_alias_map(cache_hit_miss_map));
664 global_field_list.add(field, false);
665 field_symbol_hash.emplace("chm", field);
666
667 field = new LogField("proxy_response_all_header_fields", "psah", LogField::STRING,
668 &LogAccess::marshal_proxy_resp_all_header_fields, &LogUtils::unmarshalMimeHdr);
669 global_field_list.add(field, false);
670 field_symbol_hash.emplace("psah", field);
671
672 // proxy -> server fields
673 field = new LogField("proxy_req_header_len", "pqhl", LogField::sINT, &LogAccess::marshal_proxy_req_header_len,
674 &LogAccess::unmarshal_int_to_str);
675 global_field_list.add(field, false);
676 field_symbol_hash.emplace("pqhl", field);
677
678 field = new LogField("proxy_req_squid_len", "pqql", LogField::sINT, &LogAccess::marshal_proxy_req_squid_len,
679 &LogAccess::unmarshal_int_to_str);
680 global_field_list.add(field, false);
681 field_symbol_hash.emplace("pqql", field);
682
683 field = new LogField("proxy_req_content_len", "pqcl", LogField::sINT, &LogAccess::marshal_proxy_req_content_len,
684 &LogAccess::unmarshal_int_to_str);
685 global_field_list.add(field, false);
686 field_symbol_hash.emplace("pqcl", field);
687
688 field = new LogField("proxy_req_server_ip", "pqsi", LogField::IP, &LogAccess::marshal_proxy_req_server_ip,
689 &LogAccess::unmarshal_ip_to_str);
690 global_field_list.add(field, false);
691 field_symbol_hash.emplace("pqsi", field);
692
693 field = new LogField("proxy_req_server_port", "pqsp", LogField::sINT, &LogAccess::marshal_proxy_req_server_port,
694 &LogAccess::unmarshal_int_to_str);
695 global_field_list.add(field, false);
696 field_symbol_hash.emplace("pqsp", field);
697
698 field = new LogField("next_hop_ip", "nhi", LogField::IP, &LogAccess::marshal_next_hop_ip, &LogAccess::unmarshal_ip_to_str);
699 global_field_list.add(field, false);
700 field_symbol_hash.emplace("nhi", field);
701
702 field = new LogField("next_hop_port", "nhp", LogField::IP, &LogAccess::marshal_next_hop_port, &LogAccess::unmarshal_int_to_str);
703 global_field_list.add(field, false);
704 field_symbol_hash.emplace("nhp", field);
705
706 Ptr<LogFieldAliasTable> hierarchy_map = make_ptr(new LogFieldAliasTable);
707 hierarchy_map->init(
708 36, SQUID_HIER_EMPTY, "EMPTY", SQUID_HIER_NONE, "NONE", SQUID_HIER_DIRECT, "DIRECT", SQUID_HIER_SIBLING_HIT, "SIBLING_HIT",
709 SQUID_HIER_PARENT_HIT, "PARENT_HIT", SQUID_HIER_DEFAULT_PARENT, "DEFAULT_PARENT", SQUID_HIER_SINGLE_PARENT, "SINGLE_PARENT",
710 SQUID_HIER_FIRST_UP_PARENT, "FIRST_UP_PARENT", SQUID_HIER_NO_PARENT_DIRECT, "NO_PARENT_DIRECT", SQUID_HIER_FIRST_PARENT_MISS,
711 "FIRST_PARENT_MISS", SQUID_HIER_LOCAL_IP_DIRECT, "LOCAL_IP_DIRECT", SQUID_HIER_FIREWALL_IP_DIRECT, "FIREWALL_IP_DIRECT",
712 SQUID_HIER_NO_DIRECT_FAIL, "NO_DIRECT_FAIL", SQUID_HIER_SOURCE_FASTEST, "SOURCE_FASTEST", SQUID_HIER_SIBLING_UDP_HIT_OBJ,
713 "SIBLING_UDP_HIT_OBJ", SQUID_HIER_PARENT_UDP_HIT_OBJ, "PARENT_UDP_HIT_OBJ", SQUID_HIER_PASSTHROUGH_PARENT, "PASSTHROUGH_PARENT",
714 SQUID_HIER_SSL_PARENT_MISS, "SSL_PARENT_MISS", SQUID_HIER_INVALID_CODE, "INVALID_CODE", SQUID_HIER_TIMEOUT_DIRECT,
715 "TIMEOUT_DIRECT", SQUID_HIER_TIMEOUT_SIBLING_HIT, "TIMEOUT_SIBLING_HIT", SQUID_HIER_TIMEOUT_PARENT_HIT, "TIMEOUT_PARENT_HIT",
716 SQUID_HIER_TIMEOUT_DEFAULT_PARENT, "TIMEOUT_DEFAULT_PARENT", SQUID_HIER_TIMEOUT_SINGLE_PARENT, "TIMEOUT_SINGLE_PARENT",
717 SQUID_HIER_TIMEOUT_FIRST_UP_PARENT, "TIMEOUT_FIRST_UP_PARENT", SQUID_HIER_TIMEOUT_NO_PARENT_DIRECT, "TIMEOUT_NO_PARENT_DIRECT",
718 SQUID_HIER_TIMEOUT_FIRST_PARENT_MISS, "TIMEOUT_FIRST_PARENT_MISS", SQUID_HIER_TIMEOUT_LOCAL_IP_DIRECT,
719 "TIMEOUT_LOCAL_IP_DIRECT", SQUID_HIER_TIMEOUT_FIREWALL_IP_DIRECT, "TIMEOUT_FIREWALL_IP_DIRECT",
720 SQUID_HIER_TIMEOUT_NO_DIRECT_FAIL, "TIMEOUT_NO_DIRECT_FAIL", SQUID_HIER_TIMEOUT_SOURCE_FASTEST, "TIMEOUT_SOURCE_FASTEST",
721 SQUID_HIER_TIMEOUT_SIBLING_UDP_HIT_OBJ, "TIMEOUT_SIBLING_UDP_HIT_OBJ", SQUID_HIER_TIMEOUT_PARENT_UDP_HIT_OBJ,
722 "TIMEOUT_PARENT_UDP_HIT_OBJ", SQUID_HIER_TIMEOUT_PASSTHROUGH_PARENT, "TIMEOUT_PASSTHROUGH_PARENT",
723 SQUID_HIER_TIMEOUT_TIMEOUT_SSL_PARENT_MISS, "TIMEOUT_TIMEOUT_SSL_PARENT_MISS", SQUID_HIER_INVALID_ASSIGNED_CODE,
724 "INVALID_ASSIGNED_CODE");
725
726 field = new LogField("proxy_hierarchy_route", "phr", LogField::sINT, &LogAccess::marshal_proxy_hierarchy_route,
727 &LogAccess::unmarshal_hierarchy, make_alias_map(hierarchy_map));
728 global_field_list.add(field, false);
729 field_symbol_hash.emplace("phr", field);
730
731 field = new LogField("proxy_host_name", "phn", LogField::STRING, &LogAccess::marshal_proxy_host_name,
732 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
733 global_field_list.add(field, false);
734 field_symbol_hash.emplace("phn", field);
735
736 field = new LogField("proxy_host_ip", "phi", LogField::IP, &LogAccess::marshal_proxy_host_ip, &LogAccess::unmarshal_ip_to_str);
737 global_field_list.add(field, false);
738 field_symbol_hash.emplace("phi", field);
739
740 field =
741 new LogField("proxy_host_port", "php", LogField::sINT, &LogAccess::marshal_proxy_host_port, &LogAccess::unmarshal_int_to_str);
742 global_field_list.add(field, false);
743 field_symbol_hash.emplace("php", field);
744
745 field = new LogField("proxy_req_is_ssl", "pqssl", LogField::sINT, &LogAccess::marshal_proxy_req_is_ssl,
746 &LogAccess::unmarshal_int_to_str);
747 global_field_list.add(field, false);
748 field_symbol_hash.emplace("pqssl", field);
749
750 field = new LogField("proxy_request_all_header_fields", "pqah", LogField::STRING, &LogAccess::marshal_proxy_req_all_header_fields,
751 &LogUtils::unmarshalMimeHdr);
752 global_field_list.add(field, false);
753 field_symbol_hash.emplace("pqah", field);
754
755 // server -> proxy fields
756 field = new LogField("server_host_ip", "shi", LogField::IP, &LogAccess::marshal_server_host_ip, &LogAccess::unmarshal_ip_to_str);
757
758 global_field_list.add(field, false);
759 field_symbol_hash.emplace("shi", field);
760
761 field = new LogField("server_host_name", "shn", LogField::STRING, &LogAccess::marshal_server_host_name,
762 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
763 global_field_list.add(field, false);
764 field_symbol_hash.emplace("shn", field);
765
766 field = new LogField("server_resp_status_code", "sssc", LogField::sINT, &LogAccess::marshal_server_resp_status_code,
767 &LogAccess::unmarshal_http_status);
768 global_field_list.add(field, false);
769 field_symbol_hash.emplace("sssc", field);
770
771 field = new LogField("server_resp_content_len", "sscl", LogField::sINT, &LogAccess::marshal_server_resp_content_len,
772 &LogAccess::unmarshal_int_to_str);
773 global_field_list.add(field, false);
774 field_symbol_hash.emplace("sscl", field);
775
776 field = new LogField("server_resp_header_len", "sshl", LogField::sINT, &LogAccess::marshal_server_resp_header_len,
777 &LogAccess::unmarshal_int_to_str);
778 global_field_list.add(field, false);
779 field_symbol_hash.emplace("sshl", field);
780
781 field = new LogField("server_resp_squid_len", "ssql", LogField::sINT, &LogAccess::marshal_server_resp_squid_len,
782 &LogAccess::unmarshal_int_to_str);
783 global_field_list.add(field, false);
784 field_symbol_hash.emplace("ssql", field);
785
786 field = new LogField("server_resp_http_version", "sshv", LogField::dINT, &LogAccess::marshal_server_resp_http_version,
787 &LogAccess::unmarshal_http_version);
788 global_field_list.add(field, false);
789 field_symbol_hash.emplace("sshv", field);
790
791 field = new LogField("server_resp_time", "stms", LogField::sINT, &LogAccess::marshal_server_resp_time_ms,
792 &LogAccess::unmarshal_int_to_str);
793 global_field_list.add(field, false);
794 field_symbol_hash.emplace("stms", field);
795
796 field = new LogField("server_resp_time_hex", "stmsh", LogField::sINT, &LogAccess::marshal_server_resp_time_ms,
797 &LogAccess::unmarshal_int_to_str_hex);
798 global_field_list.add(field, false);
799 field_symbol_hash.emplace("stmsh", field);
800
801 field = new LogField("server_resp_time_fractional", "stmsf", LogField::sINT, &LogAccess::marshal_server_resp_time_ms,
802 &LogAccess::unmarshal_ttmsf);
803 global_field_list.add(field, false);
804 field_symbol_hash.emplace("stmsf", field);
805
806 field = new LogField("server_resp_time_sec", "sts", LogField::sINT, &LogAccess::marshal_server_resp_time_s,
807 &LogAccess::unmarshal_int_to_str);
808 global_field_list.add(field, false);
809 field_symbol_hash.emplace("sts", field);
810
811 field = new LogField("server_transact_count", "sstc", LogField::sINT, &LogAccess::marshal_server_transact_count,
812 &LogAccess::unmarshal_int_to_str);
813 global_field_list.add(field, false);
814 field_symbol_hash.emplace("sstc", field);
815
816 field = new LogField("server_connect_attempts", "sca", LogField::sINT, &LogAccess::marshal_server_connect_attempts,
817 &LogAccess::unmarshal_int_to_str);
818 global_field_list.add(field, false);
819 field_symbol_hash.emplace("sca", field);
820
821 field = new LogField("origin_response_all_header_fields", "ssah", LogField::STRING,
822 &LogAccess::marshal_server_resp_all_header_fields, &LogUtils::unmarshalMimeHdr);
823 global_field_list.add(field, false);
824 field_symbol_hash.emplace("ssah", field);
825
826 field = new LogField("cached_resp_status_code", "csssc", LogField::sINT, &LogAccess::marshal_cache_resp_status_code,
827 &LogAccess::unmarshal_http_status);
828 global_field_list.add(field, false);
829 field_symbol_hash.emplace("csssc", field);
830
831 field = new LogField("cached_resp_content_len", "csscl", LogField::sINT, &LogAccess::marshal_cache_resp_content_len,
832 &LogAccess::unmarshal_int_to_str);
833 global_field_list.add(field, false);
834 field_symbol_hash.emplace("csscl", field);
835
836 field = new LogField("cached_resp_header_len", "csshl", LogField::sINT, &LogAccess::marshal_cache_resp_header_len,
837 &LogAccess::unmarshal_int_to_str);
838 global_field_list.add(field, false);
839 field_symbol_hash.emplace("csshl", field);
840
841 field = new LogField("cached_resp_squid_len", "cssql", LogField::sINT, &LogAccess::marshal_cache_resp_squid_len,
842 &LogAccess::unmarshal_int_to_str);
843 global_field_list.add(field, false);
844 field_symbol_hash.emplace("cssql", field);
845
846 field = new LogField("cached_resp_http_version", "csshv", LogField::dINT, &LogAccess::marshal_cache_resp_http_version,
847 &LogAccess::unmarshal_http_version);
848 global_field_list.add(field, false);
849 field_symbol_hash.emplace("csshv", field);
850
851 field = new LogField("cache_origin_response_all_header_fields", "cssah", LogField::STRING,
852 &LogAccess::marshal_cache_resp_all_header_fields, &LogUtils::unmarshalMimeHdr);
853 global_field_list.add(field, false);
854 field_symbol_hash.emplace("cssah", field);
855
856 field = new LogField("client_retry_after_time", "crat", LogField::sINT, &LogAccess::marshal_client_retry_after_time,
857 &LogAccess::unmarshal_int_to_str);
858 global_field_list.add(field, false);
859 field_symbol_hash.emplace("crat", field);
860
861 // cache write fields
862
863 Ptr<LogFieldAliasTable> cache_write_code_map = make_ptr(new LogFieldAliasTable);
864 cache_write_code_map->init(N_LOG_CACHE_WRITE_TYPES, LOG_CACHE_WRITE_NONE, "-", LOG_CACHE_WRITE_LOCK_MISSED, "WL_MISS",
865 LOG_CACHE_WRITE_LOCK_ABORTED, "INTR", LOG_CACHE_WRITE_ERROR, "ERR", LOG_CACHE_WRITE_COMPLETE, "FIN");
866 field = new LogField("cache_write_result", "cwr", LogField::sINT, &LogAccess::marshal_cache_write_code,
867 &LogAccess::unmarshal_cache_write_code, make_alias_map(cache_write_code_map));
868 global_field_list.add(field, false);
869 field_symbol_hash.emplace("cwr", field);
870
871 field = new LogField("cache_write_transform_result", "cwtr", LogField::sINT, &LogAccess::marshal_cache_write_transform_code,
872 &LogAccess::unmarshal_cache_write_code, make_alias_map(cache_write_code_map));
873 global_field_list.add(field, false);
874 field_symbol_hash.emplace("cwtr", field);
875
876 // other fields
877
878 field = new LogField("transfer_time_ms", "ttms", LogField::sINT, &LogAccess::marshal_transfer_time_ms,
879 &LogAccess::unmarshal_int_to_str);
880 global_field_list.add(field, false);
881 field_symbol_hash.emplace("ttms", field);
882
883 field = new LogField("transfer_time_ms_hex", "ttmh", LogField::sINT, &LogAccess::marshal_transfer_time_ms,
884 &LogAccess::unmarshal_int_to_str_hex);
885 global_field_list.add(field, false);
886 field_symbol_hash.emplace("ttmh", field);
887
888 field = new LogField("transfer_time_ms_fractional", "ttmsf", LogField::sINT, &LogAccess::marshal_transfer_time_ms,
889 &LogAccess::unmarshal_ttmsf);
890 global_field_list.add(field, false);
891 field_symbol_hash.emplace("ttmsf", field);
892
893 field =
894 new LogField("transfer_time_sec", "tts", LogField::sINT, &LogAccess::marshal_transfer_time_s, &LogAccess::unmarshal_int_to_str);
895 global_field_list.add(field, false);
896 field_symbol_hash.emplace("tts", field);
897
898 field = new LogField("file_size", "fsiz", LogField::sINT, &LogAccess::marshal_file_size, &LogAccess::unmarshal_int_to_str);
899 global_field_list.add(field, false);
900 field_symbol_hash.emplace("fsiz", field);
901
902 field = new LogField("client_connection_id", "ccid", LogField::sINT, &LogAccess::marshal_client_http_connection_id,
903 &LogAccess::unmarshal_int_to_str);
904 global_field_list.add(field, false);
905 field_symbol_hash.emplace("ccid", field);
906
907 field = new LogField("client_transaction_id", "ctid", LogField::sINT, &LogAccess::marshal_client_http_transaction_id,
908 &LogAccess::unmarshal_int_to_str);
909 global_field_list.add(field, false);
910 field_symbol_hash.emplace("ctid", field);
911
912 field = new LogField("cache_read_retry_attempts", "crra", LogField::dINT, &LogAccess::marshal_cache_read_retries,
913 &LogAccess::unmarshal_int_to_str);
914 global_field_list.add(field, false);
915 field_symbol_hash.emplace("crra", field);
916
917 field = new LogField("cache_write_retry_attempts", "cwra", LogField::dINT, &LogAccess::marshal_cache_write_retries,
918 &LogAccess::unmarshal_int_to_str);
919 global_field_list.add(field, false);
920 field_symbol_hash.emplace("cwra", field);
921
922 field = new LogField("cache_collapsed_connection_success", "cccs", LogField::dINT,
923 &LogAccess::marshal_cache_collapsed_connection_success, &LogAccess::unmarshal_int_to_str);
924 global_field_list.add(field, false);
925 field_symbol_hash.emplace("cccs", field);
926
927 field = new LogField("client_transaction_priority_weight", "ctpw", LogField::sINT,
928 &LogAccess::marshal_client_http_transaction_priority_weight, &LogAccess::unmarshal_int_to_str);
929 global_field_list.add(field, false);
930 field_symbol_hash.emplace("ctpw", field);
931
932 field = new LogField("client_transaction_priority_dependence", "ctpd", LogField::sINT,
933 &LogAccess::marshal_client_http_transaction_priority_dependence, &LogAccess::unmarshal_int_to_str);
934 global_field_list.add(field, false);
935 field_symbol_hash.emplace("ctpd", field);
936
937 field = new LogField("proxy_protocol_version", "ppv", LogField::dINT, &LogAccess::marshal_proxy_protocol_version,
938 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
939 global_field_list.add(field, false);
940 field_symbol_hash.emplace("ppv", field);
941
942 field = new LogField("proxy_protocol_src_ip", "pps", LogField::IP, &LogAccess::marshal_proxy_protocol_src_ip,
943 &LogAccess::unmarshal_ip_to_str);
944 global_field_list.add(field, false);
945 field_symbol_hash.emplace("ppsip", field);
946
947 field = new LogField("proxy_protocol_dst_ip", "ppd", LogField::IP, &LogAccess::marshal_proxy_protocol_dst_ip,
948 &LogAccess::unmarshal_ip_to_str);
949 global_field_list.add(field, false);
950 field_symbol_hash.emplace("ppdip", field);
951
952 field = new LogField("version_build_number", "vbn", LogField::STRING, &LogAccess::marshal_version_build_number,
953 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
954 global_field_list.add(field, false);
955 field_symbol_hash.emplace("vbn", field);
956
957 field = new LogField("version_string", "vs", LogField::STRING, &LogAccess::marshal_version_string,
958 reinterpret_cast<LogField::UnmarshalFunc>(&LogAccess::unmarshal_str));
959 global_field_list.add(field, false);
960 field_symbol_hash.emplace("vs", field);
961
962 init_status |= FIELDS_INITIALIZED;
963 }
964
965 /*-------------------------------------------------------------------------
966
967 Initialization functions
968
969 -------------------------------------------------------------------------*/
970 int
handle_logging_mode_change(const char *,RecDataT,RecData,void *)971 Log::handle_logging_mode_change(const char * /* name ATS_UNUSED */, RecDataT /* data_type ATS_UNUSED */,
972 RecData /* data ATS_UNUSED */, void * /* cookie ATS_UNUSED */)
973 {
974 Debug("log-config", "Enabled status changed");
975 logging_mode_changed = true;
976 return 0;
977 }
978
979 int
handle_periodic_tasks_int_change(const char *,RecDataT,RecData data,void *)980 Log::handle_periodic_tasks_int_change(const char * /* name ATS_UNUSED */, RecDataT /* data_type ATS_UNUSED */, RecData data,
981 void * /* cookie ATS_UNSED */)
982 {
983 Debug("log-periodic", "periodic task interval changed");
984 if (data.rec_int <= 0) {
985 periodic_tasks_interval = PERIODIC_TASKS_INTERVAL_FALLBACK;
986 Error("new periodic tasks interval = %d is invalid, falling back to default = %d", (int)data.rec_int,
987 PERIODIC_TASKS_INTERVAL_FALLBACK);
988 } else {
989 periodic_tasks_interval = static_cast<uint32_t>(data.rec_int);
990 Debug("log-periodic", "periodic task interval changed to %u", periodic_tasks_interval);
991 }
992 return REC_ERR_OKAY;
993 }
994
995 int
handle_log_rotation_request()996 Log::handle_log_rotation_request()
997 {
998 Debug("log", "Request to reopen rotated log files.");
999 log_rotate_signal_received = true;
1000 return 0;
1001 }
1002
1003 void
init(int flags)1004 Log::init(int flags)
1005 {
1006 preproc_threads = 1;
1007
1008 // store the configuration flags
1009 //
1010 config_flags = flags;
1011
1012 // create the configuration object
1013 config = new LogConfig();
1014 ink_assert(config != nullptr);
1015
1016 log_configid = configProcessor.set(log_configid, config);
1017
1018 // set the logging_mode and read config variables if needed
1019 //
1020 if (config_flags & LOGCAT) {
1021 logging_mode = LOG_MODE_NONE;
1022 } else {
1023 log_rsb = RecAllocateRawStatBlock(static_cast<int>(log_stat_count));
1024 LogConfig::register_stat_callbacks();
1025
1026 config->read_configuration_variables();
1027 preproc_threads = config->preproc_threads;
1028
1029 int val = static_cast<int>(REC_ConfigReadInteger("proxy.config.log.logging_enabled"));
1030 if (val < LOG_MODE_NONE || val > LOG_MODE_FULL) {
1031 logging_mode = LOG_MODE_FULL;
1032 Warning("proxy.config.log.logging_enabled has an invalid "
1033 "value, setting it to %d",
1034 logging_mode);
1035 } else {
1036 logging_mode = static_cast<LoggingMode>(val);
1037 }
1038 // periodic task interval are set on a per instance basis
1039 MgmtInt pti = REC_ConfigReadInteger("proxy.config.log.periodic_tasks_interval");
1040 if (pti <= 0) {
1041 Error("proxy.config.log.periodic_tasks_interval = %" PRId64 " is invalid", pti);
1042 Note("falling back to default periodic tasks interval = %d", PERIODIC_TASKS_INTERVAL_FALLBACK);
1043 periodic_tasks_interval = PERIODIC_TASKS_INTERVAL_FALLBACK;
1044 } else {
1045 periodic_tasks_interval = static_cast<uint32_t>(pti);
1046 }
1047
1048 REC_RegisterConfigUpdateFunc("proxy.config.log.periodic_tasks_interval", &Log::handle_periodic_tasks_int_change, nullptr);
1049 }
1050
1051 // if remote management is enabled, do all necessary initialization to
1052 // be able to handle a logging mode change
1053 //
1054 if (!(config_flags & NO_REMOTE_MANAGEMENT)) {
1055 REC_RegisterConfigUpdateFunc("proxy.config.log.logging_enabled", &Log::handle_logging_mode_change, nullptr);
1056
1057 // Clear any stat values that need to be reset on startup
1058 //
1059 RecSetRawStatSum(log_rsb, log_stat_log_files_open_stat, 0);
1060 RecSetRawStatCount(log_rsb, log_stat_log_files_open_stat, 0);
1061 }
1062
1063 init_fields();
1064 if (!(config_flags & LOGCAT)) {
1065 Debug("log-config", "Log::init(): logging_mode = %d init status = %d", logging_mode, init_status);
1066 config->init();
1067 init_when_enabled();
1068 }
1069 }
1070
1071 void
init_when_enabled()1072 Log::init_when_enabled()
1073 {
1074 // make sure the log config has been initialized
1075 ink_release_assert(config->initialized == true);
1076
1077 if (!(init_status & FULLY_INITIALIZED)) {
1078 // register callbacks
1079 //
1080 if (!(config_flags & NO_REMOTE_MANAGEMENT)) {
1081 LogConfig::register_config_callbacks();
1082 }
1083
1084 LogConfig::register_mgmt_callbacks();
1085
1086 // create the flush thread
1087 create_threads();
1088 eventProcessor.schedule_every(new PeriodicWakeup(preproc_threads, 1), HRTIME_SECOND, ET_CALL);
1089
1090 init_status |= FULLY_INITIALIZED;
1091 }
1092
1093 Note("logging initialized[%d], logging_mode = %d", init_status, logging_mode);
1094 if (is_debug_tag_set("log-config")) {
1095 config->display();
1096 }
1097 }
1098
1099 void
create_threads()1100 Log::create_threads()
1101 {
1102 char desc[64];
1103 preproc_notify = new EventNotify[preproc_threads];
1104
1105 size_t stacksize;
1106 REC_ReadConfigInteger(stacksize, "proxy.config.thread.default.stacksize");
1107
1108 // start the preproc threads
1109 //
1110 // no need for the conditional var since it will be relying on
1111 // on the event system.
1112 for (int i = 0; i < preproc_threads; i++) {
1113 Continuation *preproc_cont = new LoggingPreprocContinuation(i);
1114 sprintf(desc, "[LOG_PREPROC %d]", i);
1115 eventProcessor.spawn_thread(preproc_cont, desc, stacksize);
1116 }
1117
1118 // Now, only one flush thread is supported.
1119 // TODO: Enable multiple flush threads, such as
1120 // one flush thread per file.
1121 //
1122 flush_notify = new EventNotify;
1123 flush_data_list = new InkAtomicList;
1124
1125 ink_atomiclist_init(flush_data_list, "Logging flush buffer list", 0);
1126 Continuation *flush_cont = new LoggingFlushContinuation(0);
1127 eventProcessor.spawn_thread(flush_cont, "[LOG_FLUSH]", stacksize);
1128 }
1129
1130 /*-------------------------------------------------------------------------
1131 Log::access
1132
1133 Make an entry in the access log for the data supplied by the given
1134 LogAccess object.
1135 -------------------------------------------------------------------------*/
1136
1137 int
access(LogAccess * lad)1138 Log::access(LogAccess *lad)
1139 {
1140 // See if transaction logging is disabled
1141 //
1142 if (!transaction_logging_enabled()) {
1143 return Log::SKIP;
1144 }
1145
1146 ink_assert(init_status & FULLY_INITIALIZED);
1147 ink_assert(lad != nullptr);
1148
1149 int ret;
1150 static long sample = 1;
1151 long this_sample;
1152 ProxyMutex *mutex = this_ethread()->mutex.get();
1153
1154 // See if we're sampling and it is not time for another sample
1155 //
1156 if (Log::config->sampling_frequency > 1) {
1157 this_sample = sample++;
1158 if (this_sample && this_sample % Log::config->sampling_frequency) {
1159 Debug("log", "sampling, skipping this entry ...");
1160 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_event_log_access_skip_stat, 1);
1161 ret = Log::SKIP;
1162 goto done;
1163 } else {
1164 Debug("log", "sampling, LOGGING this entry ...");
1165 sample = 1;
1166 }
1167 }
1168
1169 if (Log::config->log_object_manager.get_num_objects() == 0) {
1170 Debug("log", "no log objects, skipping this entry ...");
1171 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_event_log_access_skip_stat, 1);
1172 ret = Log::SKIP;
1173 goto done;
1174 }
1175 // initialize this LogAccess object and process
1176 //
1177 lad->init();
1178 ret = config->log_object_manager.log(lad);
1179
1180 done:
1181 return ret;
1182 }
1183
1184 /*-------------------------------------------------------------------------
1185 Log::error
1186
1187 Make an entry into the current error log. For convenience, it is given in
1188 both variable argument (format, ...) and stdarg (format, va_list) forms.
1189 -------------------------------------------------------------------------*/
1190
1191 int
error(const char * format,...)1192 Log::error(const char *format, ...)
1193 {
1194 va_list ap;
1195 int ret;
1196
1197 va_start(ap, format);
1198 ret = Log::va_error(format, ap);
1199 va_end(ap);
1200
1201 return ret;
1202 }
1203
1204 int
va_error(const char * format,va_list ap)1205 Log::va_error(const char *format, va_list ap)
1206 {
1207 int ret_val = Log::SKIP;
1208 ProxyMutex *mutex = this_ethread()->mutex.get();
1209
1210 if (error_log) {
1211 ink_assert(format != nullptr);
1212 ret_val = error_log->va_log(nullptr, format, ap);
1213
1214 switch (ret_val) {
1215 case Log::LOG_OK:
1216 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_event_log_error_ok_stat, 1);
1217 break;
1218 case Log::SKIP:
1219 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_event_log_error_skip_stat, 1);
1220 break;
1221 case Log::AGGR:
1222 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_event_log_error_aggr_stat, 1);
1223 break;
1224 case Log::FULL:
1225 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_event_log_error_full_stat, 1);
1226 break;
1227 case Log::FAIL:
1228 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_event_log_error_fail_stat, 1);
1229 break;
1230 default:
1231 ink_release_assert(!"Unexpected result");
1232 }
1233
1234 return ret_val;
1235 }
1236
1237 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_event_log_error_skip_stat, 1);
1238
1239 return ret_val;
1240 }
1241
1242 /*-------------------------------------------------------------------------
1243 Log::trace
1244
1245 These functions are used for wiretracing of incoming SSL connections.
1246 They are an extension of the existing Log::error functionality but with
1247 special formatting and handling of the non null terminated buffer.
1248 -------------------------------------------------------------------------*/
1249
1250 void
trace_in(const sockaddr * peer_addr,uint16_t peer_port,const char * format_string,...)1251 Log::trace_in(const sockaddr *peer_addr, uint16_t peer_port, const char *format_string, ...)
1252 {
1253 va_list ap;
1254 va_start(ap, format_string);
1255 trace_va(true, peer_addr, peer_port, format_string, ap);
1256 va_end(ap);
1257 }
1258
1259 void
trace_out(const sockaddr * peer_addr,uint16_t peer_port,const char * format_string,...)1260 Log::trace_out(const sockaddr *peer_addr, uint16_t peer_port, const char *format_string, ...)
1261 {
1262 va_list ap;
1263 va_start(ap, format_string);
1264 trace_va(false, peer_addr, peer_port, format_string, ap);
1265 va_end(ap);
1266 }
1267
1268 void
trace_va(bool in,const sockaddr * peer_addr,uint16_t peer_port,const char * format_string,va_list ap)1269 Log::trace_va(bool in, const sockaddr *peer_addr, uint16_t peer_port, const char *format_string, va_list ap)
1270 {
1271 if (!peer_addr || !format_string) {
1272 return;
1273 }
1274
1275 char ip[INET6_ADDRSTRLEN];
1276 ats_ip_ntop(peer_addr, ip, sizeof(ip));
1277
1278 struct timeval tp = ink_gettimeofday();
1279
1280 Log::error("[%9d.%03d] Trace {0x%" PRIx64 "} %s %s:%d: ", static_cast<int>(tp.tv_sec), static_cast<int>(tp.tv_usec / 1000),
1281 reinterpret_cast<uint64_t>(ink_thread_self()), in ? "RECV" : "SEND", ip, peer_port);
1282 Log::va_error(format_string, ap);
1283 Log::error("[End Trace]\n");
1284 }
1285
1286 /*-------------------------------------------------------------------------
1287 Log::preproc_thread_main
1288
1289 This function defines the functionality of the logging flush preprocess
1290 thread, whose purpose is to consume full LogBuffer objects, do some prepare
1291 work (such as convert to ascii), and then forward to flush thread.
1292 -------------------------------------------------------------------------*/
1293
1294 void *
preproc_thread_main(void * args)1295 Log::preproc_thread_main(void *args)
1296 {
1297 int idx = *static_cast<int *>(args);
1298
1299 Debug("log-preproc", "log preproc thread is alive ...");
1300
1301 Log::preproc_notify[idx].lock();
1302
1303 while (true) {
1304 if (TSSystemState::is_event_system_shut_down()) {
1305 return nullptr;
1306 }
1307 LogConfig *current = static_cast<LogConfig *>(configProcessor.get(log_configid));
1308
1309 if (likely(current)) {
1310 size_t buffers_preproced = current->log_object_manager.preproc_buffers(idx);
1311
1312 // config->increment_space_used(bytes_to_disk);
1313 // TODO: the bytes_to_disk should be set to Log
1314
1315 Debug("log-preproc", "%zu buffers preprocessed from LogConfig %p (refcount=%d) this round", buffers_preproced, current,
1316 current->refcount());
1317
1318 configProcessor.release(log_configid, current);
1319 }
1320
1321 // wait for more work; a spurious wake-up is ok since we'll just
1322 // check the queue and find there is nothing to do, then wait
1323 // again.
1324 //
1325 Log::preproc_notify[idx].wait();
1326 }
1327
1328 /* NOTREACHED */
1329 Log::preproc_notify[idx].unlock();
1330 return nullptr;
1331 }
1332
1333 void *
flush_thread_main(void *)1334 Log::flush_thread_main(void * /* args ATS_UNUSED */)
1335 {
1336 LogBuffer *logbuffer;
1337 LogFlushData *fdata;
1338 ink_hrtime now, last_time = 0;
1339 int len, total_bytes;
1340 SLL<LogFlushData, LogFlushData::Link_link> link, invert_link;
1341 ProxyMutex *mutex = this_thread()->mutex.get();
1342
1343 Log::flush_notify->lock();
1344
1345 while (true) {
1346 if (TSSystemState::is_event_system_shut_down()) {
1347 return nullptr;
1348 }
1349 fdata = static_cast<LogFlushData *>(ink_atomiclist_popall(flush_data_list));
1350
1351 // invert the list
1352 //
1353 link.head = fdata;
1354 while ((fdata = link.pop())) {
1355 invert_link.push(fdata);
1356 }
1357
1358 // process each flush data
1359 //
1360 while ((fdata = invert_link.pop())) {
1361 char *buf = nullptr;
1362 int bytes_written = 0;
1363 LogFile *logfile = fdata->m_logfile.get();
1364
1365 if (logfile->m_file_format == LOG_FILE_BINARY) {
1366 logbuffer = static_cast<LogBuffer *>(fdata->m_data);
1367 LogBufferHeader *buffer_header = logbuffer->header();
1368
1369 buf = reinterpret_cast<char *>(buffer_header);
1370 total_bytes = buffer_header->byte_count;
1371
1372 } else if (logfile->m_file_format == LOG_FILE_ASCII || logfile->m_file_format == LOG_FILE_PIPE) {
1373 buf = static_cast<char *>(fdata->m_data);
1374 total_bytes = fdata->m_len;
1375
1376 } else {
1377 ink_release_assert(!"Unknown file format type!");
1378 }
1379
1380 // make sure we're open & ready to write
1381 logfile->check_fd();
1382 if (!logfile->is_open()) {
1383 Warning("File:%s was closed, have dropped (%d) bytes.", logfile->get_name(), total_bytes);
1384
1385 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_bytes_lost_before_written_to_disk_stat, total_bytes);
1386 delete fdata;
1387 continue;
1388 }
1389
1390 int logfilefd = logfile->get_fd();
1391 // This should always be true because we just checked it.
1392 ink_assert(logfilefd >= 0);
1393
1394 // write *all* data to target file as much as possible
1395 //
1396 while (total_bytes - bytes_written) {
1397 if (Log::config->logging_space_exhausted) {
1398 Debug("log", "logging space exhausted, failed to write file:%s, have dropped (%d) bytes.", logfile->get_name(),
1399 (total_bytes - bytes_written));
1400
1401 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_bytes_lost_before_written_to_disk_stat,
1402 total_bytes - bytes_written);
1403 break;
1404 }
1405
1406 len = ::write(logfilefd, &buf[bytes_written], total_bytes - bytes_written);
1407
1408 if (len < 0) {
1409 Error("Failed to write log to %s: [tried %d, wrote %d, %s]", logfile->get_name(), total_bytes - bytes_written,
1410 bytes_written, strerror(errno));
1411
1412 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_bytes_lost_before_written_to_disk_stat,
1413 total_bytes - bytes_written);
1414 break;
1415 }
1416 Debug("log", "Successfully wrote some stuff to %s", logfile->get_name());
1417 bytes_written += len;
1418 }
1419
1420 RecIncrRawStat(log_rsb, mutex->thread_holding, log_stat_bytes_written_to_disk_stat, bytes_written);
1421
1422 if (logfile->m_log) {
1423 ink_atomic_increment(&logfile->m_log->m_bytes_written, bytes_written);
1424 }
1425
1426 delete fdata;
1427 }
1428
1429 // Time to work on periodic events??
1430 //
1431 now = Thread::get_hrtime() / HRTIME_SECOND;
1432 if (now >= last_time + periodic_tasks_interval) {
1433 Debug("log-preproc", "periodic tasks for %" PRId64, (int64_t)now);
1434 periodic_tasks(now);
1435 last_time = Thread::get_hrtime() / HRTIME_SECOND;
1436 }
1437
1438 // wait for more work; a spurious wake-up is ok since we'll just
1439 // check the queue and find there is nothing to do, then wait
1440 // again.
1441 //
1442 Log::flush_notify->wait();
1443 }
1444
1445 /* NOTREACHED */
1446 Log::flush_notify->unlock();
1447 return nullptr;
1448 }
1449