@@ -94,7 +94,6 @@ class PatternFormatter
94
94
/* **/
95
95
~PatternFormatter () = default ;
96
96
97
- /* **/
98
97
QUILL_NODISCARD QUILL_ATTRIBUTE_HOT std::string_view format (
99
98
uint64_t timestamp, std::string_view thread_id, std::string_view thread_name,
100
99
std::string_view process_id, std::string_view logger, std::string_view log_level_description,
@@ -109,122 +108,59 @@ class PatternFormatter
109
108
return std::string_view{};
110
109
}
111
110
112
- // clear out existing buffer
111
+ // clear out the existing buffer
113
112
_formatted_log_message_buffer.clear ();
114
113
115
- if (_is_set_in_pattern[Attribute::Time])
116
- {
117
- _set_arg_val<Attribute::Time>(_timestamp_formatter.format_timestamp (std::chrono::nanoseconds{timestamp}));
118
- }
119
-
120
- if (_is_set_in_pattern[Attribute::FileName])
121
- {
122
- _set_arg_val<Attribute::FileName>(log_statement_metadata.file_name ());
123
- }
124
-
125
- if (_is_set_in_pattern[Attribute::CallerFunction])
126
- {
127
- std::string_view const function_name = _options.process_function_name
128
- ? _options.process_function_name (log_statement_metadata.caller_function ())
129
- : std::string_view{log_statement_metadata.caller_function ()};
130
-
131
- _set_arg_val<Attribute::CallerFunction>(function_name);
132
- }
133
-
134
- if (_is_set_in_pattern[Attribute::LogLevel])
135
- {
136
- _set_arg_val<Attribute::LogLevel>(log_level_description);
137
- }
138
-
139
- if (_is_set_in_pattern[Attribute::LogLevelShortCode])
140
- {
141
- _set_arg_val<Attribute::LogLevelShortCode>(log_level_short_code);
142
- }
143
-
144
- if (_is_set_in_pattern[Attribute::LineNumber])
145
- {
146
- _set_arg_val<Attribute::LineNumber>(log_statement_metadata.line ());
147
- }
148
-
149
- if (_is_set_in_pattern[Attribute::Logger])
150
- {
151
- _set_arg_val<Attribute::Logger>(logger);
152
- }
153
-
154
- if (_is_set_in_pattern[Attribute::FullPath])
155
- {
156
- _set_arg_val<Attribute::FullPath>(log_statement_metadata.full_path ());
157
- }
158
-
159
- if (_is_set_in_pattern[Attribute::ThreadId])
114
+ if (QUILL_UNLIKELY (log_msg.empty ()))
160
115
{
161
- _set_arg_val<Attribute::ThreadId>(thread_id);
116
+ // Process an empty message
117
+ return _format (timestamp, thread_id, thread_name, process_id, logger, log_level_description,
118
+ log_level_short_code, log_statement_metadata, named_args, log_msg);
162
119
}
163
120
164
- if (_is_set_in_pattern[Attribute::ThreadName])
165
- {
166
- _set_arg_val<Attribute::ThreadName>(thread_name);
167
- }
121
+ std::string_view formatted_log_msg;
168
122
169
- if (_is_set_in_pattern[Attribute::ProcessId])
123
+ // Check if we need to handle multi-line formatting
124
+ if (_options.add_metadata_to_multi_line_logs && (!named_args || named_args->empty ()))
170
125
{
171
- _set_arg_val<Attribute::ProcessId>(process_id);
172
- }
126
+ // multi line metadata only supported when named_args are not used
127
+ size_t start = 0 ;
173
128
174
- if (_is_set_in_pattern[Attribute::SourceLocation])
175
- {
176
- _set_arg_val<Attribute::SourceLocation>(_process_source_location_path (
177
- log_statement_metadata.source_location (), _options.source_location_path_strip_prefix ,
178
- _options.source_location_remove_relative_paths ));
179
- ;
180
- }
181
-
182
- if (_is_set_in_pattern[Attribute::ShortSourceLocation])
183
- {
184
- _set_arg_val<Attribute::ShortSourceLocation>(log_statement_metadata.short_source_location ());
185
- }
186
-
187
- if (_is_set_in_pattern[Attribute::NamedArgs])
188
- {
189
- _formatted_named_args_buffer.clear ();
190
-
191
- if (named_args)
129
+ while (start < log_msg.size ())
192
130
{
193
- for (size_t i = 0 ; i < named_args->size (); ++i)
194
- {
195
- _formatted_named_args_buffer.append ((*named_args)[i].first );
196
- _formatted_named_args_buffer.append (std::string_view{" : " });
197
- _formatted_named_args_buffer.append ((*named_args)[i].second );
131
+ size_t const end = log_msg.find_first_of (' \n ' , start);
198
132
199
- if (i != named_args->size () - 1 )
200
- {
201
- _formatted_named_args_buffer.append (std::string_view{" , " });
202
- }
133
+ if (end == std::string_view::npos)
134
+ {
135
+ // Handle the last line or a single line without a newline
136
+ formatted_log_msg =
137
+ _format (timestamp, thread_id, thread_name, process_id, logger, log_level_description,
138
+ log_level_short_code, log_statement_metadata, named_args,
139
+ std::string_view (log_msg.data () + start, log_msg.size () - start));
140
+ break ;
203
141
}
204
- }
205
142
206
- _set_arg_val<Attribute::NamedArgs>(
207
- std::string_view{_formatted_named_args_buffer. data (), _formatted_named_args_buffer. size ()});
208
- }
143
+ // Write the current line
144
+ formatted_log_msg = _format (timestamp, thread_id, thread_name, process_id, logger, log_level_description,
145
+ log_level_short_code, log_statement_metadata, named_args, std::string_view (log_msg. data () + start, end - start));
209
146
210
- if (_is_set_in_pattern[Attribute::Tags])
211
- {
212
- if (log_statement_metadata.tags ())
213
- {
214
- _set_arg_val<Attribute::Tags>(std::string_view{log_statement_metadata.tags ()});
215
- }
216
- else
217
- {
218
- _set_arg_val<Attribute::Tags>(std::string_view{});
147
+ start = end + 1 ;
219
148
}
220
149
}
150
+ else
151
+ {
152
+ // Use the regular format method for single-line messages
221
153
222
- _set_arg_val<Attribute::Message>(log_msg);
154
+ // if the log_message ends with \n we should exclude it
155
+ assert (!log_msg.empty () && " Already checked non empty message earlier" );
156
+ size_t const log_message_size =
157
+ (log_msg[log_msg.size () - 1 ] == ' \n ' ) ? log_msg.size () - 1 : log_msg.size ();
223
158
224
- fmtquill::vformat_to (std::back_inserter (_formatted_log_message_buffer), _fmt_format,
225
- fmtquill::basic_format_args (_args.data (), static_cast <int >(_args.size ())));
159
+ formatted_log_msg = _format (timestamp, thread_id, thread_name, process_id, logger, log_level_description,
160
+ log_level_short_code, log_statement_metadata, named_args, std::string_view{log_msg.data (), log_message_size});
161
+ }
226
162
227
- return std::string_view{_formatted_log_message_buffer. data (), _formatted_log_message_buffer. size ()} ;
163
+ return formatted_log_msg ;
228
164
}
229
165
230
166
/* **/
@@ -513,6 +449,128 @@ class PatternFormatter
513
449
return std::make_pair (pattern, order_index);
514
450
}
515
451
452
+ /* **/
453
+ QUILL_ATTRIBUTE_HOT std::string_view _format (
454
+ uint64_t timestamp, std::string_view thread_id, std::string_view thread_name,
455
+ std::string_view process_id, std::string_view logger, std::string_view log_level_description,
456
+ std::string_view log_level_short_code, MacroMetadata const & log_statement_metadata,
457
+ std::vector<std::pair<std::string, std::string>> const * named_args, std::string_view log_msg)
458
+ {
459
+ if (_is_set_in_pattern[Attribute::Time])
460
+ {
461
+ _set_arg_val<Attribute::Time>(_timestamp_formatter.format_timestamp (std::chrono::nanoseconds{timestamp}));
462
+ }
463
+
464
+ if (_is_set_in_pattern[Attribute::FileName])
465
+ {
466
+ _set_arg_val<Attribute::FileName>(log_statement_metadata.file_name ());
467
+ }
468
+
469
+ if (_is_set_in_pattern[Attribute::CallerFunction])
470
+ {
471
+ std::string_view const function_name = _options.process_function_name
472
+ ? _options.process_function_name (log_statement_metadata.caller_function ())
473
+ : std::string_view{log_statement_metadata.caller_function ()};
474
+
475
+ _set_arg_val<Attribute::CallerFunction>(function_name);
476
+ }
477
+
478
+ if (_is_set_in_pattern[Attribute::LogLevel])
479
+ {
480
+ _set_arg_val<Attribute::LogLevel>(log_level_description);
481
+ }
482
+
483
+ if (_is_set_in_pattern[Attribute::LogLevelShortCode])
484
+ {
485
+ _set_arg_val<Attribute::LogLevelShortCode>(log_level_short_code);
486
+ }
487
+
488
+ if (_is_set_in_pattern[Attribute::LineNumber])
489
+ {
490
+ _set_arg_val<Attribute::LineNumber>(log_statement_metadata.line ());
491
+ }
492
+
493
+ if (_is_set_in_pattern[Attribute::Logger])
494
+ {
495
+ _set_arg_val<Attribute::Logger>(logger);
496
+ }
497
+
498
+ if (_is_set_in_pattern[Attribute::FullPath])
499
+ {
500
+ _set_arg_val<Attribute::FullPath>(log_statement_metadata.full_path ());
501
+ }
502
+
503
+ if (_is_set_in_pattern[Attribute::ThreadId])
504
+ {
505
+ _set_arg_val<Attribute::ThreadId>(thread_id);
506
+ }
507
+
508
+ if (_is_set_in_pattern[Attribute::ThreadName])
509
+ {
510
+ _set_arg_val<Attribute::ThreadName>(thread_name);
511
+ }
512
+
513
+ if (_is_set_in_pattern[Attribute::ProcessId])
514
+ {
515
+ _set_arg_val<Attribute::ProcessId>(process_id);
516
+ }
517
+
518
+ if (_is_set_in_pattern[Attribute::SourceLocation])
519
+ {
520
+ _set_arg_val<Attribute::SourceLocation>(_process_source_location_path (
521
+ log_statement_metadata.source_location (), _options.source_location_path_strip_prefix ,
522
+ _options.source_location_remove_relative_paths ));
523
+ ;
524
+ }
525
+
526
+ if (_is_set_in_pattern[Attribute::ShortSourceLocation])
527
+ {
528
+ _set_arg_val<Attribute::ShortSourceLocation>(log_statement_metadata.short_source_location ());
529
+ }
530
+
531
+ if (_is_set_in_pattern[Attribute::NamedArgs])
532
+ {
533
+ _formatted_named_args_buffer.clear ();
534
+
535
+ if (named_args)
536
+ {
537
+ for (size_t i = 0 ; i < named_args->size (); ++i)
538
+ {
539
+ _formatted_named_args_buffer.append ((*named_args)[i].first );
540
+ _formatted_named_args_buffer.append (std::string_view{" : " });
541
+ _formatted_named_args_buffer.append ((*named_args)[i].second );
542
+
543
+ if (i != named_args->size () - 1 )
544
+ {
545
+ _formatted_named_args_buffer.append (std::string_view{" , " });
546
+ }
547
+ }
548
+ }
549
+
550
+ _set_arg_val<Attribute::NamedArgs>(
551
+ std::string_view{_formatted_named_args_buffer.data (), _formatted_named_args_buffer.size ()});
552
+ }
553
+
554
+ if (_is_set_in_pattern[Attribute::Tags])
555
+ {
556
+ if (log_statement_metadata.tags ())
557
+ {
558
+ _set_arg_val<Attribute::Tags>(std::string_view{log_statement_metadata.tags ()});
559
+ }
560
+ else
561
+ {
562
+ _set_arg_val<Attribute::Tags>(std::string_view{});
563
+ }
564
+ }
565
+
566
+ _set_arg_val<Attribute::Message>(log_msg);
567
+
568
+ fmtquill::vformat_to (std::back_inserter (_formatted_log_message_buffer), _fmt_format,
569
+ fmtquill::basic_format_args (_args.data (), static_cast <int >(_args.size ())));
570
+
571
+ return std::string_view{_formatted_log_message_buffer.data (), _formatted_log_message_buffer.size ()};
572
+ }
573
+
516
574
private:
517
575
PatternFormatterOptions _options;
518
576
std::string _fmt_format;
0 commit comments