90 }
91 }
92
93 void LogConfiguration::initialize(jlong vm_start_time) {
94 LogFileOutput::set_file_name_parameters(vm_start_time);
95 LogDecorations::initialize(vm_start_time);
96 assert(_outputs == NULL, "Should not initialize _outputs before this function, initialize called twice?");
97 _outputs = NEW_C_HEAP_ARRAY(LogOutput*, 2, mtLogging);
98 _outputs[0] = LogOutput::Stdout;
99 _outputs[1] = LogOutput::Stderr;
100 _n_outputs = 2;
101 }
102
103 void LogConfiguration::finalize() {
104 for (size_t i = 2; i < _n_outputs; i++) {
105 delete _outputs[i];
106 }
107 FREE_C_HEAP_ARRAY(LogOutput*, _outputs);
108 }
109
110 size_t LogConfiguration::find_output(const char* name) {
111 for (size_t i = 0; i < _n_outputs; i++) {
112 if (strcmp(_outputs[i]->name(), name) == 0) {
113 return i;
114 }
115 }
116 return SIZE_MAX;
117 }
118
119 LogOutput* LogConfiguration::new_output(char* name, const char* options, outputStream* errstream) {
120 const char* type;
121 char* equals_pos = strchr(name, '=');
122 if (equals_pos == NULL) {
123 type = "file";
124 } else {
125 *equals_pos = '\0';
126 type = name;
127 name = equals_pos + 1;
128 }
129
130 // Check if name is quoted, and if so, strip the quotes
131 char* quote = strchr(name, '"');
132 if (quote != NULL) {
133 char* end_quote = strchr(name + 1, '"');
134 if (end_quote == NULL) {
135 errstream->print_cr("Output name has opening quote but is missing a terminating quote.");
136 return NULL;
137 } else if (quote != name || end_quote[1] != '\0') {
138 errstream->print_cr("Output name can not be partially quoted."
139 " Either surround the whole name with quotation marks,"
140 " or do not use quotation marks at all.");
141 return NULL;
142 }
143 name++;
144 *end_quote = '\0';
145 }
146
147 LogOutput* output;
148 if (strcmp(type, "file") == 0) {
149 output = new LogFileOutput(name);
150 } else {
151 errstream->print_cr("Unsupported log output type.");
152 return NULL;
153 }
154
155 bool success = output->initialize(options, errstream);
156 if (!success) {
157 errstream->print_cr("Initialization of output '%s' using options '%s' failed.", name, options);
158 delete output;
159 return NULL;
160 }
161 return output;
162 }
163
164 size_t LogConfiguration::add_output(LogOutput* output) {
165 size_t idx = _n_outputs++;
166 _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
167 _outputs[idx] = output;
168 return idx;
169 }
170
171 void LogConfiguration::delete_output(size_t idx) {
347 const char* what,
348 const char* decoratorstr,
349 const char* output_options,
350 outputStream* errstream) {
351 if (outputstr == NULL || strlen(outputstr) == 0) {
352 outputstr = "stdout";
353 }
354
355 LogTagLevelExpression expr;
356 if (!expr.parse(what, errstream)) {
357 return false;
358 }
359
360 LogDecorators decorators;
361 if (!decorators.parse(decoratorstr, errstream)) {
362 return false;
363 }
364
365 ConfigurationLock cl;
366 size_t idx;
367 if (outputstr[0] == '#') {
368 int ret = sscanf(outputstr+1, SIZE_FORMAT, &idx);
369 if (ret != 1 || idx >= _n_outputs) {
370 errstream->print_cr("Invalid output index '%s'", outputstr);
371 return false;
372 }
373 } else {
374 idx = find_output(outputstr);
375 if (idx == SIZE_MAX) {
376 char* tmp = os::strdup_check_oom(outputstr, mtLogging);
377 LogOutput* output = new_output(tmp, output_options, errstream);
378 os::free(tmp);
379 if (output == NULL) {
380 return false;
381 }
382 idx = add_output(output);
383 } else if (output_options != NULL && strlen(output_options) > 0) {
384 errstream->print_cr("Output options for existing outputs are ignored.");
385 }
386 }
387 configure_output(idx, expr, decorators);
388 notify_update_listeners();
389 return true;
390 }
391
392 void LogConfiguration::describe_available(outputStream* out){
393 out->print("Available log levels:");
394 for (size_t i = 0; i < LogLevel::Count; i++) {
395 out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
396 }
397 out->cr();
398
399 out->print("Available log decorators:");
400 for (size_t i = 0; i < LogDecorators::Count; i++) {
401 LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
402 out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
403 }
404 out->cr();
|
90 }
91 }
92
93 void LogConfiguration::initialize(jlong vm_start_time) {
94 LogFileOutput::set_file_name_parameters(vm_start_time);
95 LogDecorations::initialize(vm_start_time);
96 assert(_outputs == NULL, "Should not initialize _outputs before this function, initialize called twice?");
97 _outputs = NEW_C_HEAP_ARRAY(LogOutput*, 2, mtLogging);
98 _outputs[0] = LogOutput::Stdout;
99 _outputs[1] = LogOutput::Stderr;
100 _n_outputs = 2;
101 }
102
103 void LogConfiguration::finalize() {
104 for (size_t i = 2; i < _n_outputs; i++) {
105 delete _outputs[i];
106 }
107 FREE_C_HEAP_ARRAY(LogOutput*, _outputs);
108 }
109
110 // Normalizes the given LogOutput name to type=name form.
111 static bool normalize_output_name(const char* full_name, char* buffer, size_t len, outputStream* errstream) {
112 const char* start_quote = strchr(full_name, '"');
113 const char* equals = strchr(full_name, '=');
114 const bool quoted = start_quote != NULL;
115 const bool is_stdout_or_stderr = (strcmp(full_name, "stdout") == 0 || strcmp(full_name, "stderr") == 0);
116
117 // ignore equals sign within quotes
118 if (quoted && equals > start_quote) {
119 equals = NULL;
120 }
121
122 const char* prefix = "";
123 size_t prefix_len = 0;
124 const char* name = full_name;
125 if (equals != NULL) {
126 // split on equals sign
127 name = equals + 1;
128 prefix = full_name;
129 prefix_len = equals - full_name + 1;
130 } else if (!is_stdout_or_stderr) {
131 prefix = "file=";
132 prefix_len = strlen(prefix);
133 }
134 size_t name_len = strlen(name);
135
136 if (quoted) {
137 const char* end_quote = strchr(start_quote + 1, '"');
138 if (end_quote == NULL) {
139 errstream->print_cr("Output name has opening quote but is missing a terminating quote.");
140 return false;
141 }
142 if (start_quote != name || end_quote[1] != '\0') {
143 errstream->print_cr("Output name can not be partially quoted."
144 " Either surround the whole name with quotation marks,"
145 " or do not use quotation marks at all.");
146 return false;
147 }
148 // strip start and end quote
149 name++;
150 name_len -= 2;
151 }
152
153 int ret = jio_snprintf(buffer, len, "%.*s%.*s", prefix_len, prefix, name_len, name);
154 assert(ret > 0, "buffer issue");
155 return true;
156 }
157
158 size_t LogConfiguration::find_output(const char* name) {
159 for (size_t i = 0; i < _n_outputs; i++) {
160 if (strcmp(_outputs[i]->name(), name) == 0) {
161 return i;
162 }
163 }
164 return SIZE_MAX;
165 }
166
167 LogOutput* LogConfiguration::new_output(const char* name,
168 const char* options,
169 outputStream* errstream) {
170 LogOutput* output;
171 if (strncmp(name, "file=", strlen("file=")) == 0) {
172 output = new LogFileOutput(name);
173 } else {
174 errstream->print_cr("Unsupported log output type: %s", name);
175 return NULL;
176 }
177
178 bool success = output->initialize(options, errstream);
179 if (!success) {
180 errstream->print_cr("Initialization of output '%s' using options '%s' failed.", name, options);
181 delete output;
182 return NULL;
183 }
184 return output;
185 }
186
187 size_t LogConfiguration::add_output(LogOutput* output) {
188 size_t idx = _n_outputs++;
189 _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
190 _outputs[idx] = output;
191 return idx;
192 }
193
194 void LogConfiguration::delete_output(size_t idx) {
370 const char* what,
371 const char* decoratorstr,
372 const char* output_options,
373 outputStream* errstream) {
374 if (outputstr == NULL || strlen(outputstr) == 0) {
375 outputstr = "stdout";
376 }
377
378 LogTagLevelExpression expr;
379 if (!expr.parse(what, errstream)) {
380 return false;
381 }
382
383 LogDecorators decorators;
384 if (!decorators.parse(decoratorstr, errstream)) {
385 return false;
386 }
387
388 ConfigurationLock cl;
389 size_t idx;
390 if (outputstr[0] == '#') { // Output specified using index
391 int ret = sscanf(outputstr + 1, SIZE_FORMAT, &idx);
392 if (ret != 1 || idx >= _n_outputs) {
393 errstream->print_cr("Invalid output index '%s'", outputstr);
394 return false;
395 }
396 } else { // Output specified using name
397 // Normalize the name, stripping quotes and ensures it includes type prefix
398 size_t len = strlen(outputstr) + strlen("file=") + 1;
399 char* normalized = NEW_C_HEAP_ARRAY(char, len, mtLogging);
400 if (!normalize_output_name(outputstr, normalized, len, errstream)) {
401 return false;
402 }
403
404 idx = find_output(normalized);
405 if (idx == SIZE_MAX) {
406 // Attempt to create and add the output
407 LogOutput* output = new_output(normalized, output_options, errstream);
408 if (output != NULL) {
409 idx = add_output(output);
410 }
411 } else if (output_options != NULL && strlen(output_options) > 0) {
412 errstream->print_cr("Output options for existing outputs are ignored.");
413 }
414
415 FREE_C_HEAP_ARRAY(char, normalized);
416 if (idx == SIZE_MAX) {
417 return false;
418 }
419 }
420 configure_output(idx, expr, decorators);
421 notify_update_listeners();
422 return true;
423 }
424
425 void LogConfiguration::describe_available(outputStream* out){
426 out->print("Available log levels:");
427 for (size_t i = 0; i < LogLevel::Count; i++) {
428 out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
429 }
430 out->cr();
431
432 out->print("Available log decorators:");
433 for (size_t i = 0; i < LogDecorators::Count; i++) {
434 LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
435 out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
436 }
437 out->cr();
|