Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/logging/logConfiguration.cpp
40930 views
1
/*
2
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
#include "precompiled.hpp"
25
#include "jvm.h"
26
#include "logging/log.hpp"
27
#include "logging/logAsyncWriter.hpp"
28
#include "logging/logConfiguration.hpp"
29
#include "logging/logDecorations.hpp"
30
#include "logging/logDecorators.hpp"
31
#include "logging/logDiagnosticCommand.hpp"
32
#include "logging/logFileOutput.hpp"
33
#include "logging/logOutput.hpp"
34
#include "logging/logSelectionList.hpp"
35
#include "logging/logStream.hpp"
36
#include "logging/logTagSet.hpp"
37
#include "memory/allocation.inline.hpp"
38
#include "memory/resourceArea.hpp"
39
#include "runtime/os.hpp"
40
#include "runtime/semaphore.hpp"
41
#include "utilities/globalDefinitions.hpp"
42
43
LogOutput** LogConfiguration::_outputs = NULL;
44
size_t LogConfiguration::_n_outputs = 0;
45
46
LogConfiguration::UpdateListenerFunction* LogConfiguration::_listener_callbacks = NULL;
47
size_t LogConfiguration::_n_listener_callbacks = 0;
48
49
// LogFileOutput is the default type of output, its type prefix should be used if no type was specified
50
static const char* implicit_output_prefix = LogFileOutput::Prefix;
51
52
// Stack object to take the lock for configuring the logging.
53
// Should only be held during the critical parts of the configuration
54
// (when calling configure_output or reading/modifying the outputs array).
55
// Thread must never block when holding this lock.
56
class ConfigurationLock : public StackObj {
57
private:
58
// Semaphore used as lock
59
static Semaphore _semaphore;
60
debug_only(static intx _locking_thread_id;)
61
public:
62
ConfigurationLock() {
63
_semaphore.wait();
64
debug_only(_locking_thread_id = os::current_thread_id());
65
}
66
~ConfigurationLock() {
67
debug_only(_locking_thread_id = -1);
68
_semaphore.signal();
69
}
70
debug_only(static bool current_thread_has_lock();)
71
};
72
73
Semaphore ConfigurationLock::_semaphore(1);
74
#ifdef ASSERT
75
intx ConfigurationLock::_locking_thread_id = -1;
76
bool ConfigurationLock::current_thread_has_lock() {
77
return _locking_thread_id == os::current_thread_id();
78
}
79
#endif
80
81
void LogConfiguration::post_initialize() {
82
// Reset the reconfigured status of all outputs
83
for (size_t i = 0; i < _n_outputs; i++) {
84
_outputs[i]->_reconfigured = false;
85
}
86
87
LogDiagnosticCommand::registerCommand();
88
Log(logging) log;
89
if (log.is_info()) {
90
log.info("Log configuration fully initialized.");
91
log_develop_info(logging)("Develop logging is available.");
92
93
LogStream info_stream(log.info());
94
describe_available(&info_stream);
95
96
LogStream debug_stream(log.debug());
97
LogTagSet::list_all_tagsets(&debug_stream);
98
99
ConfigurationLock cl;
100
describe_current_configuration(&info_stream);
101
}
102
}
103
104
void LogConfiguration::initialize(jlong vm_start_time) {
105
LogFileOutput::set_file_name_parameters(vm_start_time);
106
assert(_outputs == NULL, "Should not initialize _outputs before this function, initialize called twice?");
107
_outputs = NEW_C_HEAP_ARRAY(LogOutput*, 2, mtLogging);
108
_outputs[0] = &StdoutLog;
109
_outputs[1] = &StderrLog;
110
_n_outputs = 2;
111
}
112
113
void LogConfiguration::finalize() {
114
disable_outputs();
115
FREE_C_HEAP_ARRAY(LogOutput*, _outputs);
116
}
117
118
// Normalizes the given LogOutput name to type=name form.
119
// For example, foo, "foo", file="foo", will all be normalized to file=foo (no quotes, prefixed).
120
static bool normalize_output_name(const char* full_name, char* buffer, size_t len, outputStream* errstream) {
121
const char* start_quote = strchr(full_name, '"');
122
const char* equals = strchr(full_name, '=');
123
const bool quoted = start_quote != NULL;
124
const bool is_stdout_or_stderr = (strcmp(full_name, "stdout") == 0 || strcmp(full_name, "stderr") == 0);
125
126
// ignore equals sign within quotes
127
if (quoted && equals > start_quote) {
128
equals = NULL;
129
}
130
131
const char* prefix = "";
132
size_t prefix_len = 0;
133
const char* name = full_name;
134
if (equals != NULL) {
135
// split on equals sign
136
name = equals + 1;
137
prefix = full_name;
138
prefix_len = equals - full_name + 1;
139
} else if (!is_stdout_or_stderr) {
140
prefix = implicit_output_prefix;
141
prefix_len = strlen(prefix);
142
}
143
size_t name_len = strlen(name);
144
145
if (quoted) {
146
const char* end_quote = strchr(start_quote + 1, '"');
147
if (end_quote == NULL) {
148
errstream->print_cr("Output name has opening quote but is missing a terminating quote.");
149
return false;
150
}
151
if (start_quote != name || end_quote[1] != '\0') {
152
errstream->print_cr("Output name can not be partially quoted."
153
" Either surround the whole name with quotation marks,"
154
" or do not use quotation marks at all.");
155
return false;
156
}
157
// strip start and end quote
158
name++;
159
name_len -= 2;
160
}
161
162
int ret = jio_snprintf(buffer, len, "%.*s%.*s", prefix_len, prefix, name_len, name);
163
assert(ret > 0, "buffer issue");
164
return true;
165
}
166
167
size_t LogConfiguration::find_output(const char* name) {
168
for (size_t i = 0; i < _n_outputs; i++) {
169
if (strcmp(_outputs[i]->name(), name) == 0) {
170
return i;
171
}
172
}
173
return SIZE_MAX;
174
}
175
176
LogOutput* LogConfiguration::new_output(const char* name,
177
const char* options,
178
outputStream* errstream) {
179
LogOutput* output;
180
if (strncmp(name, LogFileOutput::Prefix, strlen(LogFileOutput::Prefix)) == 0) {
181
output = new LogFileOutput(name);
182
} else {
183
errstream->print_cr("Unsupported log output type: %s", name);
184
return NULL;
185
}
186
187
bool success = output->initialize(options, errstream);
188
if (!success) {
189
errstream->print_cr("Initialization of output '%s' using options '%s' failed.", name, options);
190
delete output;
191
return NULL;
192
}
193
return output;
194
}
195
196
size_t LogConfiguration::add_output(LogOutput* output) {
197
size_t idx = _n_outputs++;
198
_outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
199
_outputs[idx] = output;
200
return idx;
201
}
202
203
void LogConfiguration::delete_output(size_t idx) {
204
assert(idx > 1 && idx < _n_outputs,
205
"idx must be in range 1 < idx < _n_outputs, but idx = " SIZE_FORMAT
206
" and _n_outputs = " SIZE_FORMAT, idx, _n_outputs);
207
LogOutput* output = _outputs[idx];
208
// Swap places with the last output and shrink the array
209
_outputs[idx] = _outputs[--_n_outputs];
210
_outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
211
delete output;
212
}
213
214
void LogConfiguration::configure_output(size_t idx, const LogSelectionList& selections, const LogDecorators& decorators) {
215
assert(ConfigurationLock::current_thread_has_lock(), "Must hold configuration lock to call this function.");
216
assert(idx < _n_outputs, "Invalid index, idx = " SIZE_FORMAT " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs);
217
LogOutput* output = _outputs[idx];
218
219
output->_reconfigured = true;
220
221
size_t on_level[LogLevel::Count] = {0};
222
223
bool enabled = false;
224
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
225
LogLevelType level = selections.level_for(*ts);
226
227
// Ignore tagsets that do not, and will not log on the output
228
if (!ts->has_output(output) && (level == LogLevel::NotMentioned || level == LogLevel::Off)) {
229
on_level[LogLevel::Off]++;
230
continue;
231
}
232
233
// Update decorators before adding/updating output level,
234
// so that the tagset will have the necessary decorators when requiring them.
235
if (level != LogLevel::Off) {
236
ts->update_decorators(decorators);
237
}
238
239
// Set the new level, if it changed
240
if (level != LogLevel::NotMentioned) {
241
ts->set_output_level(output, level);
242
} else {
243
// Look up the previously set level for this output on this tagset
244
level = ts->level_for(output);
245
}
246
247
if (level != LogLevel::Off) {
248
// Keep track of whether or not the output is ever used by some tagset
249
enabled = true;
250
}
251
252
// Track of the number of tag sets on each level
253
on_level[level]++;
254
}
255
256
// It is now safe to set the new decorators for the actual output
257
output->set_decorators(decorators);
258
259
// Update the decorators on all tagsets to get rid of unused decorators
260
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
261
ts->update_decorators();
262
}
263
264
if (!enabled && idx > 1) {
265
// User may disable a logOuput like this:
266
// LogConfiguration::parse_log_arguments(filename, "all=off", "", "", &stream);
267
// Just be conservative. Flush them all before deleting idx.
268
AsyncLogWriter::flush();
269
// Output is unused and should be removed, unless it is stdout/stderr (idx < 2)
270
delete_output(idx);
271
return;
272
}
273
274
output->update_config_string(on_level);
275
assert(strlen(output->config_string()) > 0, "should always have a config description");
276
}
277
278
void LogConfiguration::disable_outputs() {
279
size_t idx = _n_outputs;
280
281
// Remove all outputs from all tagsets.
282
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
283
ts->disable_outputs();
284
}
285
286
// Handle jcmd VM.log disable
287
// ts->disable_outputs() above has deleted output_list with RCU synchronization.
288
// Therefore, no new logging entry can enter AsyncLog buffer for the time being.
289
// flush pending entries before LogOutput instances die.
290
AsyncLogWriter::flush();
291
292
while (idx > 0) {
293
LogOutput* out = _outputs[--idx];
294
// Delete the output unless stdout or stderr (idx 0 or 1)
295
if (idx > 1) {
296
delete_output(idx);
297
} else {
298
out->set_config_string("all=off");
299
}
300
}
301
}
302
303
void LogConfiguration::disable_logging() {
304
ConfigurationLock cl;
305
disable_outputs();
306
// Update the decorators on all tagsets to get rid of unused decorators
307
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
308
ts->update_decorators();
309
}
310
notify_update_listeners();
311
}
312
313
void LogConfiguration::configure_stdout(LogLevelType level, int exact_match, ...) {
314
size_t i;
315
va_list ap;
316
LogTagType tags[LogTag::MaxTags];
317
va_start(ap, exact_match);
318
for (i = 0; i < LogTag::MaxTags; i++) {
319
LogTagType tag = static_cast<LogTagType>(va_arg(ap, int));
320
tags[i] = tag;
321
if (tag == LogTag::__NO_TAG) {
322
assert(i > 0, "Must specify at least one tag!");
323
break;
324
}
325
}
326
assert(i < LogTag::MaxTags || static_cast<LogTagType>(va_arg(ap, int)) == LogTag::__NO_TAG,
327
"Too many tags specified! Can only have up to " SIZE_FORMAT " tags in a tag set.", LogTag::MaxTags);
328
va_end(ap);
329
330
LogSelection selection(tags, !exact_match, level);
331
assert(selection.tag_sets_selected() > 0,
332
"configure_stdout() called with invalid/non-existing log selection");
333
LogSelectionList list(selection);
334
335
// Apply configuration to stdout (output #0), with the same decorators as before.
336
ConfigurationLock cl;
337
configure_output(0, list, _outputs[0]->decorators());
338
notify_update_listeners();
339
}
340
341
bool LogConfiguration::parse_command_line_arguments(const char* opts) {
342
char* copy = os::strdup_check_oom(opts, mtLogging);
343
344
// Split the option string to its colon separated components.
345
char* str = copy;
346
char* substrings[4] = {0};
347
for (int i = 0 ; i < 4; i++) {
348
substrings[i] = str;
349
350
// Find the next colon or quote
351
char* next = strpbrk(str, ":\"");
352
#ifdef _WINDOWS
353
// Skip over Windows paths such as "C:\..."
354
// Handle both C:\... and file=C:\..."
355
if (next != NULL && next[0] == ':' && next[1] == '\\') {
356
if (next == str + 1 || (strncmp(str, "file=", 5) == 0)) {
357
next = strpbrk(next + 1, ":\"");
358
}
359
}
360
#endif
361
while (next != NULL && *next == '"') {
362
char* end_quote = strchr(next + 1, '"');
363
if (end_quote == NULL) {
364
log_error(logging)("Missing terminating quote in -Xlog option '%s'", str);
365
os::free(copy);
366
return false;
367
}
368
// Keep searching after the quoted substring
369
next = strpbrk(end_quote + 1, ":\"");
370
}
371
372
if (next != NULL) {
373
*next = '\0';
374
str = next + 1;
375
} else {
376
str = NULL;
377
break;
378
}
379
}
380
381
if (str != NULL) {
382
log_warning(logging)("Ignoring excess -Xlog options: \"%s\"", str);
383
}
384
385
// Parse and apply the separated configuration options
386
char* what = substrings[0];
387
char* output = substrings[1];
388
char* decorators = substrings[2];
389
char* output_options = substrings[3];
390
char errbuf[512];
391
stringStream ss(errbuf, sizeof(errbuf));
392
bool success = parse_log_arguments(output, what, decorators, output_options, &ss);
393
394
if (ss.size() > 0) {
395
// If it failed, log the error. If it didn't fail, but something was written
396
// to the stream, log it as a warning.
397
LogLevelType level = success ? LogLevel::Warning : LogLevel::Error;
398
399
Log(logging) log;
400
char* start = errbuf;
401
char* end = strchr(start, '\n');
402
assert(end != NULL, "line must end with newline '%s'", start);
403
do {
404
assert(start < errbuf + sizeof(errbuf) &&
405
end < errbuf + sizeof(errbuf),
406
"buffer overflow");
407
*end = '\0';
408
log.write(level, "%s", start);
409
start = end + 1;
410
end = strchr(start, '\n');
411
assert(end != NULL || *start == '\0', "line must end with newline '%s'", start);
412
} while (end != NULL);
413
}
414
415
os::free(copy);
416
return success;
417
}
418
419
bool LogConfiguration::parse_log_arguments(const char* outputstr,
420
const char* selectionstr,
421
const char* decoratorstr,
422
const char* output_options,
423
outputStream* errstream) {
424
assert(errstream != NULL, "errstream can not be NULL");
425
if (outputstr == NULL || strlen(outputstr) == 0) {
426
outputstr = "stdout";
427
}
428
429
LogSelectionList selections;
430
if (!selections.parse(selectionstr, errstream)) {
431
return false;
432
}
433
434
LogDecorators decorators;
435
if (!decorators.parse(decoratorstr, errstream)) {
436
return false;
437
}
438
439
ConfigurationLock cl;
440
size_t idx;
441
bool added = false;
442
if (outputstr[0] == '#') { // Output specified using index
443
int ret = sscanf(outputstr + 1, SIZE_FORMAT, &idx);
444
if (ret != 1 || idx >= _n_outputs) {
445
errstream->print_cr("Invalid output index '%s'", outputstr);
446
return false;
447
}
448
} else { // Output specified using name
449
// Normalize the name, stripping quotes and ensures it includes type prefix
450
size_t len = strlen(outputstr) + strlen(implicit_output_prefix) + 1;
451
char* normalized = NEW_C_HEAP_ARRAY(char, len, mtLogging);
452
if (!normalize_output_name(outputstr, normalized, len, errstream)) {
453
return false;
454
}
455
456
idx = find_output(normalized);
457
if (idx == SIZE_MAX) {
458
// Attempt to create and add the output
459
LogOutput* output = new_output(normalized, output_options, errstream);
460
if (output != NULL) {
461
idx = add_output(output);
462
added = true;
463
}
464
}
465
466
FREE_C_HEAP_ARRAY(char, normalized);
467
if (idx == SIZE_MAX) {
468
return false;
469
}
470
}
471
if (!added && output_options != NULL && strlen(output_options) > 0) {
472
errstream->print_cr("Output options for existing outputs are ignored.");
473
}
474
configure_output(idx, selections, decorators);
475
notify_update_listeners();
476
selections.verify_selections(errstream);
477
return true;
478
}
479
480
void LogConfiguration::describe_available(outputStream* out) {
481
out->print("Available log levels:");
482
for (size_t i = 0; i < LogLevel::Count; i++) {
483
out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
484
}
485
out->cr();
486
487
out->print("Available log decorators:");
488
for (size_t i = 0; i < LogDecorators::Count; i++) {
489
LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
490
out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
491
}
492
out->cr();
493
494
out->print("Available log tags:");
495
LogTag::list_tags(out);
496
497
LogTagSet::describe_tagsets(out);
498
}
499
500
void LogConfiguration::describe_current_configuration(outputStream* out) {
501
out->print_cr("Log output configuration:");
502
for (size_t i = 0; i < _n_outputs; i++) {
503
out->print(" #" SIZE_FORMAT ": ", i);
504
_outputs[i]->describe(out);
505
if (_outputs[i]->is_reconfigured()) {
506
out->print(" (reconfigured)");
507
}
508
out->cr();
509
}
510
}
511
512
void LogConfiguration::describe(outputStream* out) {
513
describe_available(out);
514
ConfigurationLock cl;
515
describe_current_configuration(out);
516
}
517
518
void LogConfiguration::print_command_line_help(outputStream* out) {
519
out->print_cr("-Xlog Usage: -Xlog[:[selections][:[output][:[decorators][:output-options]]]]");
520
out->print_cr("\t where 'selections' are combinations of tags and levels of the form tag1[+tag2...][*][=level][,...]");
521
out->print_cr("\t NOTE: Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.");
522
out->cr();
523
524
out->print_cr("Available log levels:");
525
for (size_t i = 0; i < LogLevel::Count; i++) {
526
out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
527
}
528
out->cr();
529
out->cr();
530
531
out->print_cr("Available log decorators: ");
532
for (size_t i = 0; i < LogDecorators::Count; i++) {
533
LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
534
out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
535
}
536
out->cr();
537
out->print_cr(" Decorators can also be specified as 'none' for no decoration.");
538
out->cr();
539
540
out->print_cr("Available log tags:");
541
LogTag::list_tags(out);
542
out->print_cr(" Specifying 'all' instead of a tag combination matches all tag combinations.");
543
out->cr();
544
545
LogTagSet::describe_tagsets(out);
546
547
out->print_cr("\nAvailable log outputs:");
548
out->print_cr(" stdout/stderr");
549
out->print_cr(" file=<filename>");
550
out->print_cr(" If the filename contains %%p and/or %%t, they will expand to the JVM's PID and startup timestamp, respectively.");
551
out->print_cr(" Additional output-options for file outputs:");
552
out->print_cr(" filesize=.. - Target byte size for log rotation (supports K/M/G suffix)."
553
" If set to 0, log rotation will not trigger automatically,"
554
" but can be performed manually (see the VM.log DCMD).");
555
out->print_cr(" filecount=.. - Number of files to keep in rotation (not counting the active file)."
556
" If set to 0, log rotation is disabled."
557
" This will cause existing log files to be overwritten.");
558
out->cr();
559
out->print_cr("\nAsynchronous logging (off by default):");
560
out->print_cr(" -Xlog:async");
561
out->print_cr(" All log messages are written to an intermediate buffer first and will then be flushed"
562
" to the corresponding log outputs by a standalone thread. Write operations at logsites are"
563
" guaranteed non-blocking.");
564
out->cr();
565
566
out->print_cr("Some examples:");
567
out->print_cr(" -Xlog");
568
out->print_cr("\t Log all messages up to 'info' level to stdout with 'uptime', 'levels' and 'tags' decorations.");
569
out->print_cr("\t (Equivalent to -Xlog:all=info:stdout:uptime,levels,tags).");
570
out->cr();
571
572
out->print_cr(" -Xlog:gc");
573
out->print_cr("\t Log messages tagged with 'gc' tag up to 'info' level to stdout, with default decorations.");
574
out->cr();
575
576
out->print_cr(" -Xlog:gc,safepoint");
577
out->print_cr("\t Log messages tagged either with 'gc' or 'safepoint' tags, both up to 'info' level, to stdout, with default decorations.");
578
out->print_cr("\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)");
579
out->cr();
580
581
out->print_cr(" -Xlog:gc+ref=debug");
582
out->print_cr("\t Log messages tagged with both 'gc' and 'ref' tags, up to 'debug' level, to stdout, with default decorations.");
583
out->print_cr("\t (Messages tagged only with one of the two tags will not be logged.)");
584
out->cr();
585
586
out->print_cr(" -Xlog:gc=debug:file=gc.txt:none");
587
out->print_cr("\t Log messages tagged with 'gc' tag up to 'debug' level to file 'gc.txt' with no decorations.");
588
out->cr();
589
590
out->print_cr(" -Xlog:gc=trace:file=gctrace.txt:uptimemillis,pid:filecount=5,filesize=1m");
591
out->print_cr("\t Log messages tagged with 'gc' tag up to 'trace' level to a rotating fileset of 5 files of size 1MB,");
592
out->print_cr("\t using the base name 'gctrace.txt', with 'uptimemillis' and 'pid' decorations.");
593
out->cr();
594
595
out->print_cr(" -Xlog:gc::uptime,tid");
596
out->print_cr("\t Log messages tagged with 'gc' tag up to 'info' level to output 'stdout', using 'uptime' and 'tid' decorations.");
597
out->cr();
598
599
out->print_cr(" -Xlog:gc*=info,safepoint*=off");
600
out->print_cr("\t Log messages tagged with at least 'gc' up to 'info' level, but turn off logging of messages tagged with 'safepoint'.");
601
out->print_cr("\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)");
602
out->cr();
603
604
out->print_cr(" -Xlog:disable -Xlog:safepoint=trace:safepointtrace.txt");
605
out->print_cr("\t Turn off all logging, including warnings and errors,");
606
out->print_cr("\t and then enable messages tagged with 'safepoint' up to 'trace' level to file 'safepointtrace.txt'.");
607
608
out->print_cr(" -Xlog:async -Xlog:gc=debug:file=gc.log -Xlog:safepoint=trace");
609
out->print_cr("\t Write logs asynchronously. Enable messages tagged with 'safepoint' up to 'trace' level to stdout ");
610
out->print_cr("\t and messages tagged with 'gc' up to 'debug' level to file 'gc.log'.");
611
}
612
613
void LogConfiguration::rotate_all_outputs() {
614
// Start from index 2 since neither stdout nor stderr can be rotated.
615
for (size_t idx = 2; idx < _n_outputs; idx++) {
616
_outputs[idx]->force_rotate();
617
}
618
}
619
620
void LogConfiguration::register_update_listener(UpdateListenerFunction cb) {
621
assert(cb != NULL, "Should not register NULL as listener");
622
ConfigurationLock cl;
623
size_t idx = _n_listener_callbacks++;
624
_listener_callbacks = REALLOC_C_HEAP_ARRAY(UpdateListenerFunction,
625
_listener_callbacks,
626
_n_listener_callbacks,
627
mtLogging);
628
_listener_callbacks[idx] = cb;
629
}
630
631
void LogConfiguration::notify_update_listeners() {
632
assert(ConfigurationLock::current_thread_has_lock(), "notify_update_listeners must be called in ConfigurationLock scope (lock held)");
633
for (size_t i = 0; i < _n_listener_callbacks; i++) {
634
_listener_callbacks[i]();
635
}
636
}
637
638
bool LogConfiguration::_async_mode = false;
639
640