This is an automated email from the ASF dual-hosted git repository.
rmiddleton pushed a commit to branch next_stable
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git
The following commit(s) were added to refs/heads/next_stable by this push:
new de439929 LOGCXX-514 (#153)
de439929 is described below
commit de4399299954ade73d90298e7f852b943f51d4c8
Author: Robert Middleton <[email protected]>
AuthorDate: Mon Dec 5 19:26:47 2022 -0500
LOGCXX-514 (#153)
* LOGCXX-514 Create a FMTLayout that uses libfmt to format messages
---
.github/workflows/log4cxx-windows.yml | 2 +-
CMakeLists.txt | 17 +-
src/examples/cpp/CMakeLists.txt | 1 -
src/main/cpp/CMakeLists.txt | 10 +
src/main/cpp/fmtlayout.cpp | 120 +++++++++
src/main/cpp/loggingevent.cpp | 12 +-
src/main/include/log4cxx/fmtlayout.h | 272 +++++++++++++++++++++
src/main/include/log4cxx/spi/loggingevent.h | 3 +
src/test/cpp/CMakeLists.txt | 3 +
src/test/cpp/fmttest.cpp | 197 +++++++++++++++
src/test/resources/input/fmtLayout1.properties | 21 ++
src/test/resources/input/fmtLayout10.properties | 21 ++
.../resources/input/fmtLayout1_expanded.properties | 21 ++
13 files changed, 695 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/log4cxx-windows.yml
b/.github/workflows/log4cxx-windows.yml
index 2dcc0b69..012c41c0 100644
--- a/.github/workflows/log4cxx-windows.yml
+++ b/.github/workflows/log4cxx-windows.yml
@@ -58,7 +58,7 @@ jobs:
run: |
cd vcpkg
./bootstrap-vcpkg.bat
- ./vcpkg install apr apr-util --triplet=x64-windows
+ ./vcpkg install apr apr-util fmt --triplet=x64-windows
- name: 'Install zip'
id: install-zip
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 74d38ab1..fca0f7e2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,6 +63,13 @@ elseif(TARGET expat::expat)
set(EXPAT_LIBRARIES expat::expat)
endif()
+find_package(fmt 7.1 QUIET)
+if(${fmt_FOUND})
+ option(ENABLE_FMT_LAYOUT "Enable the FMT layout(if libfmt found)" ON)
+else()
+ set(ENABLE_FMT_LAYOUT "OFF")
+endif()
+
# Request C++17, if available
# This *should* fallback to an older standard if it is not available
if( NOT "${CMAKE_CXX_STANDARD}")
@@ -191,7 +198,7 @@ get_directory_property( ATOMIC_IMPL DIRECTORY
src/main/include DEFINITION ATOMIC
get_directory_property( FILESYSTEM_IMPL DIRECTORY src/main/include DEFINITION
FILESYSTEM_IMPL )
get_directory_property( STD_MAKE_UNIQUE_IMPL DIRECTORY src/main/include
DEFINITION STD_MAKE_UNIQUE_IMPL )
-foreach(varName HAS_STD_LOCALE HAS_ODBC HAS_MBSRTOWCS HAS_WCSTOMBS
HAS_FWIDE HAS_LIBESMTP HAS_SYSLOG)
+foreach(varName HAS_STD_LOCALE HAS_ODBC HAS_MBSRTOWCS HAS_WCSTOMBS
HAS_FWIDE HAS_LIBESMTP HAS_SYSLOG HAS_FMT)
if(${varName} EQUAL 0)
set(${varName} "OFF" )
elseif(${varName} EQUAL 1)
@@ -293,3 +300,11 @@ message(STATUS " ConsoleAppender ................. : ON")
message(STATUS " FileAppender .................... : ON")
message(STATUS " RollingFileAppender ............. : ON")
message(STATUS " MultiprocessRollingFileAppender . :
${LOG4CXX_MULTIPROCESS_ROLLING_FILE_APPENDER}")
+
+message(STATUS "Available layouts:")
+message(STATUS " HTMLLayout ...................... : ON")
+message(STATUS " JSONLayout ...................... : ON")
+message(STATUS " PatternLayout ................... : ON")
+message(STATUS " SimpleLayout .................... : ON")
+message(STATUS " XMLLayout ....................... : ON")
+message(STATUS " FMTLayout ....................... : ${ENABLE_FMT_LAYOUT}")
diff --git a/src/examples/cpp/CMakeLists.txt b/src/examples/cpp/CMakeLists.txt
index d8668bba..2cce6747 100644
--- a/src/examples/cpp/CMakeLists.txt
+++ b/src/examples/cpp/CMakeLists.txt
@@ -49,7 +49,6 @@ configure_file( custom-appender.xml
COPYONLY )
# Custom handling for format string example, since it utilizes libfmt
-find_package(fmt 6.0 QUIET)
if(${fmt_FOUND})
add_executable( format-string format-string.cpp )
target_compile_definitions(format-string PRIVATE
${LOG4CXX_COMPILE_DEFINITIONS} ${APR_COMPILE_DEFINITIONS}
${APR_UTIL_COMPILE_DEFINITIONS} )
diff --git a/src/main/cpp/CMakeLists.txt b/src/main/cpp/CMakeLists.txt
index 99066a10..acd4f46a 100644
--- a/src/main/cpp/CMakeLists.txt
+++ b/src/main/cpp/CMakeLists.txt
@@ -54,6 +54,12 @@ if()
)
endif()
+if(${ENABLE_FMT_LAYOUT})
+ set(extra_classes ${extra_classes}
+ fmtlayout.cpp
+ )
+endif()
+
target_sources(log4cxx
PRIVATE
action.cpp
@@ -204,6 +210,10 @@ if("${FILESYSTEM_IMPL}" STREQUAL "std::filesystem" OR
target_link_libraries(log4cxx PUBLIC
$<$<AND:$<CXX_COMPILER_ID:GNU>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,9.0>>:stdc++fs>)
endif()
+if(${ENABLE_FMT_LAYOUT})
+ target_link_libraries(log4cxx PUBLIC fmt::fmt)
+endif()
+
if(LOG4CXX_ABI_CHECK)
message("Getting dependencies for ABI compatability check...")
# Get the latest version of abi-dumper and abi-compliance-checker
diff --git a/src/main/cpp/fmtlayout.cpp b/src/main/cpp/fmtlayout.cpp
new file mode 100644
index 00000000..20b7cf54
--- /dev/null
+++ b/src/main/cpp/fmtlayout.cpp
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <log4cxx/logstring.h>
+#include <log4cxx/fmtlayout.h>
+#include <log4cxx/spi/loggingevent.h>
+#include <log4cxx/helpers/stringhelper.h>
+#include <log4cxx/helpers/pool.h>
+#include <log4cxx/helpers/optionconverter.h>
+#include <log4cxx/level.h>
+#include <chrono>
+
+#include <fmt/format.h>
+#include <fmt/chrono.h>
+
+using namespace log4cxx;
+using namespace log4cxx::spi;
+
+struct FMTLayout::FMTLayoutPrivate{
+ FMTLayoutPrivate(){}
+
+ FMTLayoutPrivate(const LogString& pattern) :
+ conversionPattern(pattern)
+ {}
+
+ LogString conversionPattern;
+};
+
+IMPLEMENT_LOG4CXX_OBJECT(FMTLayout)
+
+FMTLayout::FMTLayout() :
+ m_priv(std::make_unique<FMTLayoutPrivate>())
+{}
+
+FMTLayout::FMTLayout(const LogString& pattern) :
+ m_priv(std::make_unique<FMTLayoutPrivate>(pattern))
+{}
+
+FMTLayout::~FMTLayout(){}
+
+void FMTLayout::setConversionPattern(const LogString& pattern)
+{
+ m_priv->conversionPattern = pattern;
+ helpers::Pool pool;
+ activateOptions(pool);
+}
+
+LogString FMTLayout::getConversionPattern() const
+{
+ return m_priv->conversionPattern;
+}
+
+void FMTLayout::setOption(const LogString& option, const LogString& value)
+{
+ if (helpers::StringHelper::equalsIgnoreCase(option,
+ LOG4CXX_STR("CONVERSIONPATTERN"),
+ LOG4CXX_STR("conversionpattern")))
+ {
+ m_priv->conversionPattern =
helpers::OptionConverter::convertSpecialChars(value);
+ }
+}
+
+void FMTLayout::activateOptions(helpers::Pool&)
+{
+
+}
+
+void FMTLayout::format(LogString& output,
+ const spi::LoggingEventPtr& event,
+ log4cxx::helpers::Pool&) const
+{
+ LogString locationFull = fmt::format("{}({})",
+
event->getLocationInformation().getFileName(),
+
event->getLocationInformation().getLineNumber());
+ LogString ndc;
+ event->getNDC(ndc);
+
+ fmt::format_to(std::back_inserter(output),
+ m_priv->conversionPattern,
+ fmt::arg("d", event->getChronoTimeStamp()),
+ fmt::arg("c", event->getLoggerName()),
+ fmt::arg("logger", event->getLoggerName()),
+ fmt::arg("f",
event->getLocationInformation().getShortFileName()),
+ fmt::arg("shortfilename",
event->getLocationInformation().getShortFileName()),
+ fmt::arg("F",
event->getLocationInformation().getFileName()),
+ fmt::arg("filename",
event->getLocationInformation().getFileName()),
+ fmt::arg("l", locationFull),
+ fmt::arg("location", locationFull),
+ fmt::arg("L",
event->getLocationInformation().getLineNumber()),
+ fmt::arg("line",
event->getLocationInformation().getLineNumber()),
+ fmt::arg("m", event->getMessage()),
+ fmt::arg("message", event->getMessage()),
+ fmt::arg("M",
event->getLocationInformation().getMethodName()),
+ fmt::arg("method",
event->getLocationInformation().getMethodName()),
+ fmt::arg("n", LOG4CXX_EOL),
+ fmt::arg("newline", LOG4CXX_EOL),
+ fmt::arg("p", event->getLevel()->toString()),
+ fmt::arg("level",
event->getLevel()->toString()),
+ fmt::arg("r", event->getTimeStamp()),
+ fmt::arg("t", event->getThreadName()),
+ fmt::arg("thread", event->getThreadName()),
+ fmt::arg("T", event->getThreadUserName()),
+ fmt::arg("threadname",
event->getThreadUserName()),
+ fmt::arg("x", ndc),
+ fmt::arg("ndc", ndc)
+ );
+}
diff --git a/src/main/cpp/loggingevent.cpp b/src/main/cpp/loggingevent.cpp
index 8adcd0e6..adba3c43 100644
--- a/src/main/cpp/loggingevent.cpp
+++ b/src/main/cpp/loggingevent.cpp
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+#include <chrono>
#include <log4cxx/spi/loggingevent.h>
#include <log4cxx/ndc.h>
@@ -68,10 +69,11 @@ struct LoggingEvent::LoggingEventPrivate
ndcLookupRequired(true),
mdcCopyLookupRequired(true),
message(message1),
- timeStamp(apr_time_now()),
+ timeStamp(Date::currentTime()),
locationInfo(locationInfo1),
threadName(getCurrentThreadName()),
- threadUserName(getCurrentThreadUserName())
+ threadUserName(getCurrentThreadUserName()),
+ chronoTimeStamp(std::chrono::microseconds(timeStamp))
{
}
@@ -138,6 +140,8 @@ struct LoggingEvent::LoggingEventPrivate
* systems or SetThreadDescription on Windows.
*/
const LogString& threadUserName;
+
+ std::chrono::time_point<std::chrono::system_clock> chronoTimeStamp;
};
IMPLEMENT_LOG4CXX_OBJECT(LoggingEvent)
@@ -432,3 +436,7 @@ const log4cxx::spi::LocationInfo&
LoggingEvent::getLocationInformation() const
return m_priv->locationInfo;
}
+std::chrono::time_point<std::chrono::system_clock>
LoggingEvent::getChronoTimeStamp() const{
+ return m_priv->chronoTimeStamp;
+}
+
diff --git a/src/main/include/log4cxx/fmtlayout.h
b/src/main/include/log4cxx/fmtlayout.h
new file mode 100644
index 00000000..79fb9e28
--- /dev/null
+++ b/src/main/include/log4cxx/fmtlayout.h
@@ -0,0 +1,272 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOG4CXX_FMT_LAYOUT_H
+#define LOG4CXX_FMT_LAYOUT_H
+
+#if defined(_MSC_VER)
+ #pragma warning ( push )
+ #pragma warning ( disable: 4231 4251 4275 4786 )
+#endif
+
+
+#include <log4cxx/layout.h>
+
+namespace log4cxx
+{
+/**
+ * The FMTLayout class uses libfmt to layout messages. This is an alternative
to the PatternLayout class.
+ * Most of the standard PatternLayout arguments are also accepted as
arguments, so that you can easily
+ * convert a PatternLayout to a FMTLayout. For example, given the following
PatternLayout:
+ *
+ * <pre>%c %-5p - %m%n</pre>
+ * which outputs something like:
+ * <pre>root INFO - Hello there!</pre>
+ *
+ * The equivalent FMTLayout can be written as:
+ * <pre>{c} {p:<5} - {m}{n}</pre>
+ * Or more verbosely as:
+ * <pre>{logger} {level:<5} - {message}{newline}</pre>
+ *
+ * All replacements are done using the named arguments feature of {fmt}.
+ *
+ * <p>The recognized conversion strings are:</p>
+ *
+ * <table border="1" cellpadding="8">
+ * <tr>
+ * <th align="center"><strong>Conversion string</strong></th>
+ * <th align="center"><strong>Effect</strong></th>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>c</strong></p>
+ * <p><strong>logger</strong></p>
+ * </td>
+ * <td>
+ * Used to output the logger of the logging event. Unlike
PatternConverter,
+ * this does not take a parameter to shorten the name of the logger.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>C</strong></p>
+ * <p><strong>class</strong></p>
+ * </td>
+ * <td>
+ * Used to output the class of the issuer of the logging event if the
compiler
+ * used supports a macro to retrieve the method of the currently
compiled line and
+ * if the LOG4CXX_TRACE-like macros are used to issue a logging
request. In this
+ * case the macro LOG4CXX_* is expanded at compile time to generate
location info
+ * of the logging event and adds the method name, besides file and
line, if
+ * available. In most cases the provided method contains the
classname and can
+ * therefore be retrieved form the location info as needed.
+ * <p>
+ * Currently supported compilers are those from Microsoft, GNU-C
and Borland.
+ * </p>
+ * </td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>f</strong></p>
+ * <p><strong>shortfilename</strong></p>
+ * </td>
+ * <td>
+ * Used to output the short file name where the logging request was
issued.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>F</strong></p>
+ * <p><strong>filename</strong></p>
+ * </td>
+ * <td>
+ * Used to output the file name where the logging request was issued.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>l</strong></p>
+ * <p><strong>location</strong></p>
+ * </td>
+ * <td>
+ * Used to output location information of the caller which generated
the logging
+ * event.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>L</strong></p>
+ * <p><strong>line</strong></p>
+ * </td>
+ * <td>
+ * Used to output the line number from where the logging request was
issued.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>m</strong></p>
+ * <p><strong>message</strong></p>
+ * </td>
+ * <td>
+ * Used to output the application supplied message associated with
the logging
+ * event.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <strong>M</strong>
+ * <p><strong>method</strong></p>
+ * </td>
+ * <td>
+ * Used to output the method of the issuer of the logging event if
the compiler
+ * used supports a macro to retrieve the method of the currently
compiled line
+ * and if the LOG4CXX_TRACE-like macros are used to issue a logging
request. In
+ * this case the macro LOG4CXX_* is expanded at compile time to
generate location
+ * info of the logging event and adds the method name, besides file
and line, if
+ * available. In most cases the provided method contains the
classname which is
+ * ignored in every attempt to retrieve the method from the location
info.
+ * <p>
+ * Currently supported compilers are those from Microsoft, GNU-C
and Borland.
+ * </p>
+ * </td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>n</strong></p>
+ * <p><strong>newline</strong></p>
+ * </td>
+ * <td>
+ * Outputs the platform dependent line separator character or
characters.
+ * <p>
+ * This conversion character offers practically the same
performance as using
+ * non-portable line separator strings such as "\n", or "\r\n".
Thus, it is the
+ * preferred way of specifying a line separator.
+ * </p>
+ * </td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>p</strong></p>
+ * <p><strong>level</strong></p>
+ * </td>
+ * <td>Used to output the level of the logging event.</td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>r</strong></p>
+ * </td>
+ * <td>
+ * Used to output the number of milliseconds elapsed since the start
of the
+ * application until the creation of the logging event.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>t</strong></p>
+ * <p><strong>thread</strong></p>
+ * </td>
+ * <td>Used to output the ID of the thread that generated the logging
event.</td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>T</strong></p>
+ * <p><strong>threadname</strong></p>
+ * </td>
+ * <td>Used to output the name of the thread that generated the logging
event. May not be available on all platforms.</td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>x</strong></p>
+ * <p><strong>ndc</strong></p>
+ * </td>
+ * <td>
+ * Used to output the NDC (nested diagnostic context) associated with
the thread that
+ * generated the logging event.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td align="center">
+ * <p><strong>mdc[1-6]</strong></p>
+ * </td>
+ * <td>
+ * Used to output the MDC (mapped diagnostic context) associated with
the thread that
+ * generated the logging event. The keys must be specified in the
configuration for
+ * the layout. A maximum of 6 MDC keys are available to be
output(mdc1, mdc2, ..., mdc6)
+ * </td>
+ * </tr>
+ * </table>
+ */
+class LOG4CXX_EXPORT FMTLayout : public Layout
+{
+ LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(FMTLayoutPrivate, m_priv)
+
+ public:
+ DECLARE_LOG4CXX_OBJECT(FMTLayout)
+ BEGIN_LOG4CXX_CAST_MAP()
+ LOG4CXX_CAST_ENTRY(FMTLayout)
+ LOG4CXX_CAST_ENTRY_CHAIN(Layout)
+ END_LOG4CXX_CAST_MAP()
+
+ FMTLayout();
+
+ FMTLayout(const LogString& pattern);
+
+ ~FMTLayout();
+
+
+ /**
+ * Set the <strong>ConversionPattern</strong> option. This is
the string which
+ * controls formatting and consists of a mix of literal content
and
+ * conversion specifiers.
+ */
+ void setConversionPattern(const LogString& conversionPattern);
+
+ /**
+ * Returns the value of the <strong>ConversionPattern</strong>
option.
+ */
+ LogString getConversionPattern() const;
+
+ /**
+ Returns the log statement in a format consisting of the
+ <code>level</code>, followed by " - " and then the
+ <code>message</code>. For example, <pre> INFO - "A message"
+ </pre>
+
+ @return A byte array in SimpleLayout format.
+ */
+ void format(LogString& output,
+ const spi::LoggingEventPtr& event,
+ helpers::Pool& pool) const override;
+
+ bool ignoresThrowable() const override
+ {
+ return true;
+ }
+
+ void activateOptions(helpers::Pool& /* p */) override;
+ void setOption(const LogString& /* option */,
+ const LogString& /* value */) override;
+};
+LOG4CXX_PTR_DEF(FMTLayout);
+} // namespace log4cxx
+
+
+#if defined(_MSC_VER)
+ #pragma warning ( pop )
+#endif
+
+#endif //LOG4CXX_FMT_LAYOUT_H
diff --git a/src/main/include/log4cxx/spi/loggingevent.h
b/src/main/include/log4cxx/spi/loggingevent.h
index 55816aef..8641fcf6 100644
--- a/src/main/include/log4cxx/spi/loggingevent.h
+++ b/src/main/include/log4cxx/spi/loggingevent.h
@@ -24,6 +24,7 @@
#include <log4cxx/mdc.h>
#include <log4cxx/spi/location/locationinfo.h>
#include <vector>
+#include <chrono>
namespace log4cxx
@@ -107,6 +108,8 @@ class LOG4CXX_EXPORT LoggingEvent :
was created. */
log4cxx_time_t getTimeStamp() const;
+ std::chrono::time_point<std::chrono::system_clock>
getChronoTimeStamp() const;
+
/* Return the file where this log statement was written. */
const log4cxx::spi::LocationInfo& getLocationInformation()
const;
diff --git a/src/test/cpp/CMakeLists.txt b/src/test/cpp/CMakeLists.txt
index 0e9cad93..74a35e5b 100644
--- a/src/test/cpp/CMakeLists.txt
+++ b/src/test/cpp/CMakeLists.txt
@@ -58,6 +58,9 @@ set(ALL_LOG4CXX_TESTS
locationtest
locationdisabledtest
)
+if(${ENABLE_FMT_LAYOUT})
+ set(ALL_LOG4CXX_TESTS ${ALL_LOG4CXX_TESTS} fmttest)
+endif()
foreach(fileName IN LISTS ALL_LOG4CXX_TESTS)
add_executable(${fileName} "${fileName}.cpp")
endforeach()
diff --git a/src/test/cpp/fmttest.cpp b/src/test/cpp/fmttest.cpp
new file mode 100644
index 00000000..2b496e63
--- /dev/null
+++ b/src/test/cpp/fmttest.cpp
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "logunit.h"
+#include "testchar.h"
+#include "util/compare.h"
+#include "util/transformer.h"
+#include "util/absolutedateandtimefilter.h"
+#include "util/iso8601filter.h"
+#include "util/absolutetimefilter.h"
+#include "util/relativetimefilter.h"
+#include "util/controlfilter.h"
+#include "util/threadfilter.h"
+#include "util/linenumberfilter.h"
+#include "util/filenamefilter.h"
+#include "vectorappender.h"
+#include <log4cxx/fmtlayout.h>
+#include <log4cxx/propertyconfigurator.h>
+#include <log4cxx/helpers/date.h>
+#include <log4cxx/spi/loggingevent.h>
+#include <iostream>
+#include <iomanip>
+
+#define REGEX_STR(x) x
+#define PAT0 REGEX_STR("\\[[0-9A-FXx]*]\\ (DEBUG|INFO|WARN|ERROR|FATAL) .* -
Message [0-9]\\{1,2\\}")
+#define PAT1 ISO8601_PAT REGEX_STR(" ") PAT0
+#define PAT2 ABSOLUTE_DATE_AND_TIME_PAT REGEX_STR(" ") PAT0
+#define PAT3 ABSOLUTE_TIME_PAT REGEX_STR(" ") PAT0
+#define PAT4 RELATIVE_TIME_PAT REGEX_STR(" ") PAT0
+#define PAT5 REGEX_STR("\\[[0-9A-FXx]*]\\ (DEBUG|INFO|WARN|ERROR|FATAL) .* :
Message [0-9]\\{1,2\\}")
+#define PAT6 REGEX_STR("\\[[0-9A-FXx]*]\\ (DEBUG|INFO |WARN |ERROR|FATAL)
.*patternlayouttest.cpp\\([0-9]\\{1,4\\}\\): Message [0-9]\\{1,3\\}")
+#define PAT11a REGEX_STR("^(DEBUG|INFO |WARN |ERROR|FATAL) \\[[0-9A-FXx]*]\\
log4j.PatternLayoutTest: Message [0-9]\\{1,2\\}")
+#define PAT11b REGEX_STR("^(DEBUG|INFO |WARN |ERROR|FATAL) \\[[0-9A-FXx]*]\\
root: Message [0-9]\\{1,2\\}")
+#define PAT12 REGEX_STR("^\\[[0-9A-FXx]*]\\ (DEBUG|INFO |WARN |ERROR|FATAL) ")\
+ REGEX_STR(".*patternlayouttest.cpp([0-9]\\{1,4\\}): ")\
+ REGEX_STR("Message [0-9]\\{1,2\\}")
+#define PAT_MDC_1 REGEX_STR("")
+
+using namespace log4cxx;
+using namespace log4cxx::helpers;
+
+LOGUNIT_CLASS(FMTTestCase)
+{
+ LOGUNIT_TEST_SUITE(FMTTestCase);
+ LOGUNIT_TEST(test1);
+ LOGUNIT_TEST(test1_expanded);
+ LOGUNIT_TEST(test10);
+// LOGUNIT_TEST(test_date);
+ LOGUNIT_TEST_SUITE_END();
+
+ LoggerPtr root;
+ LoggerPtr logger;
+
+public:
+ void setUp()
+ {
+ root = Logger::getRootLogger();
+ MDC::clear();
+ logger =
Logger::getLogger(LOG4CXX_TEST_STR("java.org.apache.log4j.PatternLayoutTest"));
+ }
+
+ void tearDown()
+ {
+ MDC::clear();
+ auto rep = root->getLoggerRepository();
+
+ if (rep)
+ {
+ rep->resetConfiguration();
+ }
+ }
+
+ void test1()
+ {
+
PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout1.properties"));
+ common();
+ LOGUNIT_ASSERT(Compare::compare(TEMP,
LOG4CXX_FILE("witness/patternLayout.1")));
+ }
+
+ void test1_expanded()
+ {
+
PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout1_expanded.properties"));
+ common();
+ LOGUNIT_ASSERT(Compare::compare(TEMP,
LOG4CXX_FILE("witness/patternLayout.1")));
+ }
+
+ void test10()
+ {
+
PropertyConfigurator::configure(LOG4CXX_FILE("input/fmtLayout10.properties"));
+ common();
+
+ ControlFilter filter1;
+ filter1 << PAT6;
+ ThreadFilter filter2;
+ LineNumberFilter filter3;
+ FilenameFilter filenameFilter(__FILE__,
"patternlayouttest.cpp");
+
+
+ std::vector<Filter*> filters;
+ filters.push_back(&filenameFilter);
+ filters.push_back(&filter1);
+ filters.push_back(&filter2);
+ filters.push_back(&filter3);
+
+
+ try
+ {
+ Transformer::transform(TEMP, FILTERED, filters);
+ }
+ catch (UnexpectedFormatException& e)
+ {
+ std::cout << "UnexpectedFormatException :" << e.what()
<< std::endl;
+ throw;
+ }
+
+ LOGUNIT_ASSERT(Compare::compare(FILTERED,
LOG4CXX_FILE("witness/patternLayout.10")));
+ }
+
+ void test_date(){
+ std::tm tm = {};
+ std::stringstream ss("2013-04-11 08:35:34");
+ ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
+ auto tp =
std::chrono::system_clock::from_time_t(std::mktime(&tm));
+ uint64_t micros =
std::chrono::duration_cast<std::chrono::microseconds>(tp.time_since_epoch()).count();
+
+ log4cxx::helpers::Date::setGetCurrentTimeFunction([micros](){
+ return micros;
+ });
+
+ log4cxx::spi::LoggingEventPtr logEvt =
std::make_shared<log4cxx::spi::LoggingEvent>( "foo",
+
Level::getInfo(),
+
"A Message",
+
log4cxx::spi::LocationInfo::getLocationUnavailable());
+ FMTLayout layout("{d:%Y-%m-%d %H:%M:%S} {message}" );
+ LogString output;
+ log4cxx::helpers::Pool pool;
+ layout.format( output, logEvt, pool);
+
+ log4cxx::helpers::Date::setGetCurrentTimeFunction(nullptr);
+
+ LOGUNIT_ASSERT_EQUAL("2013-04-11 09:35:34 A Message", output);
+ }
+
+ std::string createMessage(Pool & pool, int i)
+ {
+ std::string msg("Message ");
+ msg.append(pool.itoa(i));
+ return msg;
+ }
+
+ void common()
+ {
+ int i = -1;
+
+ Pool pool;
+
+
+ LOG4CXX_DEBUG(logger, createMessage(pool, ++i));
+ LOG4CXX_DEBUG(root, createMessage(pool, i));
+
+ LOG4CXX_INFO(logger, createMessage(pool, ++i));
+ LOG4CXX_INFO(root, createMessage(pool, i));
+
+ LOG4CXX_WARN(logger, createMessage(pool, ++i));
+ LOG4CXX_WARN(root, createMessage(pool, i));
+
+ LOG4CXX_ERROR(logger, createMessage(pool, ++i));
+ LOG4CXX_ERROR(root, createMessage(pool, i));
+
+ LOG4CXX_FATAL(logger, createMessage(pool, ++i));
+ LOG4CXX_FATAL(root, createMessage(pool, i));
+ }
+
+ private:
+ static const LogString FILTERED;
+ static const LogString TEMP;
+
+};
+
+const LogString FMTTestCase::TEMP(LOG4CXX_STR("output/fmtlayout"));
+const LogString FMTTestCase::FILTERED(LOG4CXX_STR("output/fmtlayoutfiltered"));
+
+
+LOGUNIT_TEST_SUITE_REGISTRATION(FMTTestCase);
diff --git a/src/test/resources/input/fmtLayout1.properties
b/src/test/resources/input/fmtLayout1.properties
new file mode 100644
index 00000000..ecd14df4
--- /dev/null
+++ b/src/test/resources/input/fmtLayout1.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+log4j.rootCategory=DEBUG, testAppender
+log4j.appender.testAppender=org.apache.log4j.FileAppender
+log4j.appender.testAppender.file=output/fmtlayout
+log4j.appender.testAppender.Append=false
+log4j.appender.testAppender.layout=org.apache.log4j.FMTLayout
+log4j.appender.testAppender.layout.ConversionPattern={p:<5} - {m}{n}
diff --git a/src/test/resources/input/fmtLayout10.properties
b/src/test/resources/input/fmtLayout10.properties
new file mode 100644
index 00000000..3608cc74
--- /dev/null
+++ b/src/test/resources/input/fmtLayout10.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+log4j.rootCategory=DEBUG, testAppender
+log4j.appender.testAppender=org.apache.log4j.FileAppender
+log4j.appender.testAppender.File= output/fmtlayout
+log4j.appender.testAppender.Append= false
+log4j.appender.testAppender.layout=org.apache.log4j.FMTLayout
+log4j.appender.testAppender.layout.ConversionPattern=[{t}] {p:<5} {l}: {m}{n}
diff --git a/src/test/resources/input/fmtLayout1_expanded.properties
b/src/test/resources/input/fmtLayout1_expanded.properties
new file mode 100644
index 00000000..70c32d8e
--- /dev/null
+++ b/src/test/resources/input/fmtLayout1_expanded.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+log4j.rootCategory=DEBUG, testAppender
+log4j.appender.testAppender=org.apache.log4j.FileAppender
+log4j.appender.testAppender.file=output/fmtlayout
+log4j.appender.testAppender.Append=false
+log4j.appender.testAppender.layout=org.apache.log4j.FMTLayout
+log4j.appender.testAppender.layout.ConversionPattern={level:<5} -
{message}{newline}