mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-12 06:29:37 +00:00
8286180: Enable construction of LogStreamImpl from LogMessageImpl
Reviewed-by: dholmes, stefank
This commit is contained in:
parent
0c420e03ae
commit
b2ba9fc9f6
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,35 +32,35 @@
|
||||
// polluting the surrounding API with template functions.
|
||||
class LogHandle {
|
||||
private:
|
||||
LogTagSet* const _tagset;
|
||||
LogTagSet& _tagset;
|
||||
|
||||
public:
|
||||
template <LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4, LogTagType GuardTag>
|
||||
LogHandle(const LogImpl<T0, T1, T2, T3, T4, GuardTag>& type_carrier) :
|
||||
_tagset(&LogTagSetMapping<T0, T1, T2, T3, T4>::tagset()) {}
|
||||
LogHandle(const LogImpl<T0, T1, T2, T3, T4, GuardTag>& type_carrier)
|
||||
: _tagset(LogTagSetMapping<T0, T1, T2, T3, T4>::tagset()) {}
|
||||
|
||||
bool is_level(LogLevelType level) {
|
||||
return _tagset->is_level(level);
|
||||
return _tagset.is_level(level);
|
||||
}
|
||||
|
||||
LogTagSet* const tagset() const {
|
||||
LogTagSet& tagset() const {
|
||||
return _tagset;
|
||||
}
|
||||
|
||||
#define LOG_LEVEL(level, name) ATTRIBUTE_PRINTF(2, 0) \
|
||||
LogHandle& v##name(const char* fmt, va_list args) { \
|
||||
_tagset->vwrite(LogLevel::level, fmt, args); \
|
||||
_tagset.vwrite(LogLevel::level, fmt, args); \
|
||||
return *this; \
|
||||
} \
|
||||
LogHandle& name(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { \
|
||||
va_list args; \
|
||||
va_start(args, fmt); \
|
||||
_tagset->vwrite(LogLevel::level, fmt, args); \
|
||||
_tagset.vwrite(LogLevel::level, fmt, args); \
|
||||
va_end(args); \
|
||||
return *this; \
|
||||
} \
|
||||
bool is_##name() { \
|
||||
return _tagset->is_level(LogLevel::level); \
|
||||
return _tagset.is_level(LogLevel::level); \
|
||||
}
|
||||
LOG_LEVEL_LIST
|
||||
#undef LOG_LEVEL
|
||||
@ -73,15 +73,17 @@ public:
|
||||
class LogTargetHandle {
|
||||
private:
|
||||
const LogLevelType _level;
|
||||
LogTagSet* const _tagset;
|
||||
LogTagSet& _tagset;
|
||||
|
||||
public:
|
||||
LogTargetHandle(LogLevelType level, LogTagSet* const tagset) : _level(level), _tagset(tagset) {}
|
||||
LogTargetHandle(LogLevelType level, LogTagSet& tagset)
|
||||
: _level(level),
|
||||
_tagset(tagset) {}
|
||||
|
||||
template <LogLevelType level, LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4, LogTagType GuardTag>
|
||||
LogTargetHandle(const LogTargetImpl<level, T0, T1, T2, T3, T4, GuardTag>& type_carrier) :
|
||||
_level(level),
|
||||
_tagset(&LogTagSetMapping<T0, T1, T2, T3, T4>::tagset()) {}
|
||||
LogTargetHandle(const LogTargetImpl<level, T0, T1, T2, T3, T4, GuardTag>& type_carrier)
|
||||
: _level(level),
|
||||
_tagset(LogTagSetMapping<T0, T1, T2, T3, T4>::tagset()) {}
|
||||
|
||||
template <LogLevelType level, LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4, LogTagType GuardTag>
|
||||
static LogTargetHandle create() {
|
||||
@ -92,15 +94,14 @@ public:
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
if (is_enabled()) {
|
||||
_tagset->vwrite(_level, fmt, args);
|
||||
_tagset.vwrite(_level, fmt, args);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
bool is_enabled() const {
|
||||
return _tagset->is_level(_level);
|
||||
return _tagset.is_level(_level);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // SHARE_LOGGING_LOGHANDLE_HPP
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -57,19 +57,19 @@
|
||||
// Log outputs on debug level will see the debug message,
|
||||
// but not the trace message.
|
||||
//
|
||||
#define LogMessage(...) LogMessageImpl<LOG_TAGS(__VA_ARGS__)>
|
||||
template <LogTagType T0, LogTagType T1 = LogTag::__NO_TAG, LogTagType T2 = LogTag::__NO_TAG,
|
||||
LogTagType T3 = LogTag::__NO_TAG, LogTagType T4 = LogTag::__NO_TAG, LogTagType GuardTag = LogTag::__NO_TAG>
|
||||
class LogMessageImpl : public LogMessageBuffer {
|
||||
private:
|
||||
bool _has_content;
|
||||
LogTagSet& _tagset;
|
||||
public:
|
||||
LogMessageImpl() :
|
||||
_has_content(false),
|
||||
_tagset(LogTagSetMapping<T0, T1, T2, T3, T4, GuardTag>::tagset())
|
||||
{}
|
||||
#define LogMessage(...) LogMessageTemplate<LOG_TAGS(__VA_ARGS__)>
|
||||
|
||||
class LogMessageImpl : public LogMessageBuffer {
|
||||
private:
|
||||
LogTagSet& _tagset;
|
||||
bool _has_content;
|
||||
|
||||
protected:
|
||||
LogMessageImpl(LogTagSet& tagset)
|
||||
: _tagset(tagset),
|
||||
_has_content(false) {};
|
||||
|
||||
public:
|
||||
~LogMessageImpl() {
|
||||
if (_has_content) {
|
||||
flush();
|
||||
@ -90,11 +90,15 @@ class LogMessageImpl : public LogMessageBuffer {
|
||||
void vwrite(LogLevelType level, const char* fmt, va_list args) {
|
||||
if (!_has_content) {
|
||||
_has_content = true;
|
||||
set_prefix(LogPrefix<T0, T1, T2, T3, T4>::prefix);
|
||||
set_prefix(_tagset.write_prefix());
|
||||
}
|
||||
LogMessageBuffer::vwrite(level, fmt, args);
|
||||
}
|
||||
|
||||
bool is_level(LogLevelType level) const {
|
||||
return _tagset.is_level(level);
|
||||
}
|
||||
|
||||
#define LOG_LEVEL(level, name) \
|
||||
bool is_##name() const { \
|
||||
return _tagset.is_level(LogLevel::level); \
|
||||
@ -103,4 +107,13 @@ class LogMessageImpl : public LogMessageBuffer {
|
||||
#undef LOG_LEVEL
|
||||
};
|
||||
|
||||
template <LogTagType T0, LogTagType T1 = LogTag::__NO_TAG, LogTagType T2 = LogTag::__NO_TAG, LogTagType T3 = LogTag::__NO_TAG,
|
||||
LogTagType T4 = LogTag::__NO_TAG, LogTagType GuardTag = LogTag::__NO_TAG>
|
||||
class LogMessageTemplate : public LogMessageImpl {
|
||||
public:
|
||||
LogMessageTemplate(LogMessageTemplate&&) = default;
|
||||
LogMessageTemplate()
|
||||
: LogMessageImpl(LogTagSetMapping<T0, T1, T2, T3, T4>::tagset()) {}
|
||||
};
|
||||
|
||||
#endif // SHARE_LOGGING_LOGMESSAGE_HPP
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,18 +23,16 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
|
||||
LogStream::LineBuffer::LineBuffer()
|
||||
: _buf(_smallbuf), _cap(sizeof(_smallbuf)), _pos(0)
|
||||
{
|
||||
LogStreamImplBase::LineBuffer::LineBuffer()
|
||||
: _buf(_smallbuf), _cap(sizeof(_smallbuf)), _pos(0) {
|
||||
_buf[0] = '\0';
|
||||
}
|
||||
|
||||
LogStream::LineBuffer::~LineBuffer() {
|
||||
LogStreamImplBase::LineBuffer::~LineBuffer() {
|
||||
assert(_pos == 0, "still outstanding bytes in the line buffer");
|
||||
if (_buf != _smallbuf) {
|
||||
os::free(_buf);
|
||||
@ -43,51 +41,56 @@ LogStream::LineBuffer::~LineBuffer() {
|
||||
|
||||
// try_ensure_cap tries to enlarge the capacity of the internal buffer
|
||||
// to the given atleast value. May fail if either OOM happens or atleast
|
||||
// is larger than a reasonable max of 1 M. Caller must not assume
|
||||
// capacity without checking.
|
||||
void LogStream::LineBuffer::try_ensure_cap(size_t atleast) {
|
||||
// is larger than a reasonable max of 1 M.
|
||||
// Returns whether the capacity is at least atleast bytes.
|
||||
bool LogStreamImplBase::LineBuffer::try_ensure_cap(size_t atleast) {
|
||||
// Cap out at a reasonable max to prevent runaway leaks.
|
||||
const size_t reasonable_max = 1 * M;
|
||||
|
||||
assert(_cap >= sizeof(_smallbuf), "sanity");
|
||||
if (_cap < atleast) {
|
||||
// Cap out at a reasonable max to prevent runaway leaks.
|
||||
const size_t reasonable_max = 1 * M;
|
||||
assert(_cap <= reasonable_max, "sanity");
|
||||
if (_cap == reasonable_max) {
|
||||
return;
|
||||
}
|
||||
assert(_cap <= reasonable_max, "sanity");
|
||||
|
||||
const size_t additional_expansion = 256;
|
||||
size_t newcap = align_up(atleast + additional_expansion, additional_expansion);
|
||||
if (newcap > reasonable_max) {
|
||||
log_info(logging)("Suspiciously long log line: \"%.100s%s",
|
||||
_buf, (_pos >= 100 ? "..." : ""));
|
||||
newcap = reasonable_max;
|
||||
}
|
||||
|
||||
char* const newbuf = (char*) os::malloc(newcap, mtLogging);
|
||||
if (newbuf == NULL) { // OOM. Leave object unchanged.
|
||||
return;
|
||||
}
|
||||
if (_pos > 0) { // preserve old content
|
||||
memcpy(newbuf, _buf, _pos + 1); // ..including trailing zero
|
||||
}
|
||||
if (_buf != _smallbuf) {
|
||||
os::free(_buf);
|
||||
}
|
||||
_buf = newbuf;
|
||||
_cap = newcap;
|
||||
if (_cap >= atleast) {
|
||||
return true;
|
||||
}
|
||||
assert(_cap >= atleast, "sanity");
|
||||
if (_cap == reasonable_max) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t additional_expansion = 256;
|
||||
size_t newcap = align_up(atleast + additional_expansion, additional_expansion);
|
||||
|
||||
if (newcap > reasonable_max) {
|
||||
log_info(logging)("Suspiciously long log line: \"%.100s%s",
|
||||
_buf, (_pos >= 100 ? "..." : ""));
|
||||
newcap = reasonable_max;
|
||||
}
|
||||
|
||||
char* const newbuf = (char*)os::malloc(newcap, mtLogging);
|
||||
if (newbuf == NULL) { // OOM. Leave object unchanged.
|
||||
return false;
|
||||
}
|
||||
if (_pos > 0) { // preserve old content
|
||||
memcpy(newbuf, _buf, _pos + 1); // ..including trailing zero
|
||||
}
|
||||
if (_buf != _smallbuf) {
|
||||
os::free(_buf);
|
||||
}
|
||||
_buf = newbuf;
|
||||
_cap = newcap;
|
||||
|
||||
return _cap >= atleast;
|
||||
}
|
||||
|
||||
void LogStream::LineBuffer::append(const char* s, size_t len) {
|
||||
void LogStreamImplBase::LineBuffer::append(const char* s, size_t len) {
|
||||
assert(_buf[_pos] == '\0', "sanity");
|
||||
assert(_pos < _cap, "sanity");
|
||||
const size_t minimum_capacity_needed = _pos + len + 1;
|
||||
try_ensure_cap(minimum_capacity_needed);
|
||||
const bool has_capacity = try_ensure_cap(minimum_capacity_needed);
|
||||
// try_ensure_cap may not have enlarged the capacity to the full requested
|
||||
// extend or may have not worked at all. In that case, just gracefully work
|
||||
// extent or may have not worked at all. In that case, just gracefully work
|
||||
// with what we have already; just truncate if necessary.
|
||||
if (_cap < minimum_capacity_needed) {
|
||||
if (!has_capacity) {
|
||||
len = _cap - _pos - 1;
|
||||
if (len == 0) {
|
||||
return;
|
||||
@ -98,15 +101,24 @@ void LogStream::LineBuffer::append(const char* s, size_t len) {
|
||||
_buf[_pos] = '\0';
|
||||
}
|
||||
|
||||
void LogStream::LineBuffer::reset() {
|
||||
void LogStreamImplBase::LineBuffer::reset() {
|
||||
_pos = 0;
|
||||
_buf[_pos] = '\0';
|
||||
}
|
||||
|
||||
void LogStream::write(const char* s, size_t len) {
|
||||
template <typename BackingLog>
|
||||
LogStreamImpl<BackingLog>::~LogStreamImpl() {
|
||||
if (!_current_line.is_empty()) {
|
||||
_backing_log.print("%s", _current_line.buffer());
|
||||
_current_line.reset();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BackingLog>
|
||||
void LogStreamImpl<BackingLog>::write(const char* s, size_t len) {
|
||||
if (len > 0 && s[len - 1] == '\n') {
|
||||
_current_line.append(s, len - 1); // omit the newline.
|
||||
_log_handle.print("%s", _current_line.buffer());
|
||||
_backing_log.print("%s", _current_line.buffer());
|
||||
_current_line.reset();
|
||||
} else {
|
||||
_current_line.append(s, len);
|
||||
@ -114,12 +126,5 @@ void LogStream::write(const char* s, size_t len) {
|
||||
update_position(s, len);
|
||||
}
|
||||
|
||||
// Destructor writes any unfinished output left in the line buffer.
|
||||
LogStream::~LogStream() {
|
||||
if (_current_line.is_empty() == false) {
|
||||
_log_handle.print("%s", _current_line.buffer());
|
||||
_current_line.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template class LogStreamImpl<LogTargetHandle>;
|
||||
template class LogStreamImpl<LogMessageHandle>;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,14 +27,17 @@
|
||||
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logHandle.hpp"
|
||||
#include "logging/logMessage.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
|
||||
class LogStream : public outputStream {
|
||||
// see test/hotspot/gtest/logging/test_logStream.cpp
|
||||
class LogStreamImplBase : public outputStream {
|
||||
friend class LogStreamTest_TestLineBufferAllocation_vm_Test;
|
||||
friend class LogStreamTest_TestLineBufferAllocationCap_vm_Test;
|
||||
|
||||
// No heap allocation of LogStream.
|
||||
static void* operator new (size_t) = delete;
|
||||
static void* operator new[] (size_t) = delete;
|
||||
|
||||
// Helper class, maintains the line buffer. For small line lengths,
|
||||
// we avoid malloc and use a fixed sized member char array. If LogStream
|
||||
// is allocated on the stack, this means small lines are assembled
|
||||
@ -44,21 +47,49 @@ class LogStream : public outputStream {
|
||||
char* _buf;
|
||||
size_t _cap;
|
||||
size_t _pos;
|
||||
void try_ensure_cap(size_t cap);
|
||||
bool try_ensure_cap(size_t cap);
|
||||
|
||||
public:
|
||||
LineBuffer();
|
||||
~LineBuffer();
|
||||
bool is_empty() const { return _pos == 0; }
|
||||
const char* buffer() const { return _buf; }
|
||||
bool is_empty() const {
|
||||
return _pos == 0;
|
||||
}
|
||||
const char* buffer() const {
|
||||
return _buf;
|
||||
}
|
||||
void append(const char* s, size_t len);
|
||||
void reset();
|
||||
};
|
||||
LineBuffer _current_line;
|
||||
LogTargetHandle _log_handle;
|
||||
|
||||
// Prevent operator new for LogStream.
|
||||
static void* operator new (size_t);
|
||||
static void* operator new[] (size_t);
|
||||
protected:
|
||||
LineBuffer _current_line;
|
||||
};
|
||||
|
||||
template <typename BackingLog>
|
||||
class LogStreamImpl : public LogStreamImplBase {
|
||||
private:
|
||||
BackingLog _backing_log;
|
||||
|
||||
public:
|
||||
explicit LogStreamImpl(BackingLog bl)
|
||||
: _backing_log(bl) {};
|
||||
|
||||
~LogStreamImpl() override;
|
||||
|
||||
bool is_enabled() {
|
||||
return _backing_log.is_enabled();
|
||||
}
|
||||
|
||||
void write(const char* s, size_t len) override;
|
||||
};
|
||||
|
||||
class LogStream : public LogStreamImpl<LogTargetHandle> {
|
||||
// see test/hotspot/gtest/logging/test_logStream.cpp
|
||||
friend class LogStreamTest_TestLineBufferAllocation_vm_Test;
|
||||
friend class LogStreamTest_TestLineBufferAllocationCap_vm_Test;
|
||||
|
||||
NONCOPYABLE(LogStream);
|
||||
|
||||
public:
|
||||
// Constructor to support creation from a LogTarget instance.
|
||||
@ -66,8 +97,8 @@ public:
|
||||
// LogTarget(Debug, gc) log;
|
||||
// LogStream(log) stream;
|
||||
template <LogLevelType level, LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4, LogTagType GuardTag>
|
||||
LogStream(const LogTargetImpl<level, T0, T1, T2, T3, T4, GuardTag>& type_carrier) :
|
||||
_log_handle(level, &LogTagSetMapping<T0, T1, T2, T3, T4>::tagset()) {}
|
||||
LogStream(const LogTargetImpl<level, T0, T1, T2, T3, T4, GuardTag>& type_carrier)
|
||||
: LogStreamImpl(LogTargetHandle(level, LogTagSetMapping<T0, T1, T2, T3, T4>::tagset())) {}
|
||||
|
||||
// Constructor to support creation from typed (likely NULL) pointer. Mostly used by the logging framework.
|
||||
//
|
||||
@ -75,29 +106,24 @@ public:
|
||||
// or
|
||||
// LogStream stream((LogTargetImpl<level, T0, T1, T2, T3, T4, GuardTag>*)NULL);
|
||||
template <LogLevelType level, LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4, LogTagType GuardTag>
|
||||
LogStream(const LogTargetImpl<level, T0, T1, T2, T3, T4, GuardTag>* type_carrier) :
|
||||
_log_handle(level, &LogTagSetMapping<T0, T1, T2, T3, T4>::tagset()) {}
|
||||
|
||||
// Destructor writes any unfinished output left in the line buffer.
|
||||
~LogStream();
|
||||
LogStream(const LogTargetImpl<level, T0, T1, T2, T3, T4, GuardTag>* type_carrier)
|
||||
: LogStreamImpl(LogTargetHandle(level, LogTagSetMapping<T0, T1, T2, T3, T4>::tagset())) {}
|
||||
|
||||
// Constructor to support creation from a LogTargetHandle.
|
||||
//
|
||||
// LogTarget(Debug, gc) log;
|
||||
// LogTargetHandle(log) handle;
|
||||
// LogStream stream(handle);
|
||||
LogStream(LogTargetHandle handle) : _log_handle(handle) {}
|
||||
LogStream(LogTargetHandle handle)
|
||||
: LogStreamImpl(handle) {}
|
||||
|
||||
// Constructor to support creation from a log level and tagset.
|
||||
//
|
||||
// LogStream(level, tageset);
|
||||
LogStream(LogLevelType level, LogTagSet* const tagset) : _log_handle(level, tagset) {}
|
||||
LogStream(LogLevelType level, LogTagSet& tagset)
|
||||
: LogStreamImpl(LogTargetHandle(level, tagset)) {}
|
||||
|
||||
bool is_enabled() const {
|
||||
return _log_handle.is_enabled();
|
||||
}
|
||||
|
||||
void write(const char* s, size_t len);
|
||||
// Destructor writes any unfinished output left in the line buffer.
|
||||
};
|
||||
|
||||
// Support creation of a LogStream without having to provide a LogTarget pointer.
|
||||
@ -106,7 +132,36 @@ public:
|
||||
template <LogLevelType level, LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4, LogTagType GuardTag>
|
||||
class LogStreamTemplate : public LogStream {
|
||||
public:
|
||||
LogStreamTemplate() : LogStream((LogTargetImpl<level, T0, T1, T2, T3, T4, GuardTag>*)NULL) {}
|
||||
LogStreamTemplate()
|
||||
: LogStream((LogTargetImpl<level, T0, T1, T2, T3, T4, GuardTag>*)NULL) {}
|
||||
};
|
||||
|
||||
class LogMessageHandle {
|
||||
const LogLevelType _level;
|
||||
LogMessageImpl& _lm;
|
||||
|
||||
public:
|
||||
LogMessageHandle(const LogLevelType level, LogMessageImpl& lm)
|
||||
: _level(level), _lm(lm) {}
|
||||
|
||||
bool is_enabled() {
|
||||
return _lm.is_level(_level);
|
||||
}
|
||||
|
||||
void print(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
if (is_enabled()) {
|
||||
_lm.vwrite(_level, fmt, args);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
};
|
||||
|
||||
class NonInterleavingLogStream : public LogStreamImpl<LogMessageHandle> {
|
||||
public:
|
||||
NonInterleavingLogStream(LogLevelType level, LogMessageImpl& lm)
|
||||
: LogStreamImpl(LogMessageHandle(level, lm)) {}
|
||||
};
|
||||
|
||||
#endif // SHARE_LOGGING_LOGSTREAM_HPP
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -108,6 +108,10 @@ class LogTagSet {
|
||||
_output_list.clear();
|
||||
}
|
||||
|
||||
PrefixWriter write_prefix() {
|
||||
return _write_prefix;
|
||||
}
|
||||
|
||||
void set_output_level(LogOutput* output, LogLevelType level) {
|
||||
_output_list.set_output_level(output, level);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,7 +26,9 @@
|
||||
#include "logTestFixture.hpp"
|
||||
#include "logTestUtils.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logMessage.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
class LogStreamTest : public LogTestFixture {
|
||||
@ -90,6 +92,47 @@ TEST_VM_F(LogStreamTest, TestLineBufferAllocation) {
|
||||
}
|
||||
}
|
||||
|
||||
// LogStream allows interleaving of other messages.
|
||||
// Compare this to NonInterLeavingLogStreamTest_NonInterleavingStream
|
||||
TEST_VM_F(LogStreamTest, InterleavingStream) {
|
||||
set_log_config(TestLogFileName, "gc=info");
|
||||
const char* message_order[] = {"1", "I am one line", "2", "but", "3", "I am not", NULL};
|
||||
{
|
||||
LogStream foo(Log(gc)::info());
|
||||
if (foo.is_enabled()) {
|
||||
foo.print("I am");
|
||||
log_info(gc)("1");
|
||||
foo.print_cr(" one line");
|
||||
log_info(gc)("2");
|
||||
foo.print_cr("but");
|
||||
log_info(gc)("3");
|
||||
foo.print_cr("I am not");
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(file_contains_substrings_in_order(TestLogFileName, message_order));
|
||||
}
|
||||
|
||||
// NonInterleavingLogStream does not allow interleaving of other messages.
|
||||
// Compare this to LogStreamTest_InterleavingStream
|
||||
TEST_VM_F(LogStreamTest, NonInterleavingStream) {
|
||||
set_log_config(TestLogFileName, "gc=info");
|
||||
const char* message_order[] = {"1", "2" , "3", "I am one line", "but", "I am not", NULL};
|
||||
{
|
||||
LogMessage(gc) lm ;
|
||||
NonInterleavingLogStream foo{LogLevelType::Info, lm};
|
||||
if (foo.is_enabled()) {
|
||||
foo.print("I am");
|
||||
log_info(gc)("1");
|
||||
foo.print_cr(" one line");
|
||||
log_info(gc)("2");
|
||||
foo.print_cr("but");
|
||||
log_info(gc)("3");
|
||||
foo.print_cr("I am not");
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(file_contains_substrings_in_order(TestLogFileName, message_order));
|
||||
}
|
||||
|
||||
// Test, in release build, that the internal line buffer of a LogStream
|
||||
// object caps out at 1M.
|
||||
TEST_VM_F(LogStreamTest, TestLineBufferAllocationCap) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user