| /* | |
| * 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/helpers/transcoder.h> | |
| #include <log4cxx/private/layout_priv.h> | |
| #include <log4cxx/level.h> | |
| #include <chrono> | |
| #include <fmt/format.h> | |
| #include <fmt/chrono.h> | |
| #include <iterator> | |
| using namespace LOG4CXX_NS; | |
| using namespace LOG4CXX_NS::spi; | |
| struct FMTLayout::FMTLayoutPrivate{ | |
| FMTLayoutPrivate() | |
| : expectedPatternLength(100) | |
| {} | |
| FMTLayoutPrivate(const LogString& pattern) | |
| : conversionPattern(pattern) | |
| , expectedPatternLength(100) | |
| {} | |
| LogString conversionPattern; | |
| // Expected length of a formatted event excluding the message text | |
| size_t expectedPatternLength; | |
| }; | |
| 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; | |
| activateOptions(); | |
| } | |
| 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); | |
| } | |
| else | |
| Layout::setOption(option, value); | |
| } | |
| void FMTLayout::activateOptions( ) | |
| { | |
| m_priv->expectedPatternLength = priv::doubledLayoutSize(getFormattedEventCharacterCount()); | |
| } | |
| void FMTLayout::format( LogString& output, const spi::LoggingEventPtr& event ) const | |
| { | |
| auto& lsMsg = event->getRenderedMessage(); | |
| priv::reserveFormattedEvent(output, m_priv->expectedPatternLength, lsMsg.size()); | |
| auto locationFull = fmt::format("{}({})", | |
| event->getLocationInformation().getFileName(), | |
| event->getLocationInformation().getLineNumber()); | |
| LogString ndc; | |
| event->getNDC(ndc); | |
| #if LOG4CXX_LOGCHAR_IS_WCHAR | |
| LOG4CXX_ENCODE_CHAR(sNDC, ndc); | |
| LOG4CXX_ENCODE_CHAR(sPattern, m_priv->conversionPattern); | |
| LOG4CXX_ENCODE_CHAR(sLogger, event->getLoggerName()); | |
| LOG4CXX_ENCODE_CHAR(sLevel, event->getLevel()->toString()); | |
| LOG4CXX_ENCODE_CHAR(sMsg, lsMsg); | |
| LOG4CXX_ENCODE_CHAR(sThread, event->getThreadName()); | |
| LOG4CXX_ENCODE_CHAR(endOfLine, LOG4CXX_EOL); | |
| #else | |
| auto& sNDC = ndc; | |
| auto& sPattern = m_priv->conversionPattern; | |
| auto& sLogger = event->getLoggerName(); | |
| auto sLevel = event->getLevel()->toString(); | |
| auto& sMsg = lsMsg; | |
| auto& sThread = event->getThreadName(); | |
| auto endOfLine = LOG4CXX_EOL; | |
| #endif | |
| fmt::format_to(std::back_inserter(output), | |
| fmt::runtime(sPattern), | |
| fmt::arg("d", event->getChronoTimeStamp()), | |
| fmt::arg("c", sLogger), | |
| fmt::arg("logger", sLogger), | |
| 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", sMsg), | |
| fmt::arg("message", sMsg), | |
| fmt::arg("M", event->getLocationInformation().getMethodName()), | |
| fmt::arg("method", event->getLocationInformation().getMethodName()), | |
| fmt::arg("n", endOfLine), | |
| fmt::arg("newline", endOfLine), | |
| fmt::arg("p", sLevel), | |
| fmt::arg("level", sLevel), | |
| fmt::arg("r", event->getTimeStamp()), | |
| fmt::arg("t", sThread), | |
| fmt::arg("thread", sThread), | |
| fmt::arg("T", sThread), | |
| fmt::arg("threadname", sThread), | |
| fmt::arg("x", sNDC), | |
| fmt::arg("ndc", sNDC) | |
| ); | |
| } |