blob: 0b7fe0732edc76ed60f0e33ac4959215f370204d [file] [log] [blame]
/*
* 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/xml/xmllayout.h>
#include <log4cxx/spi/loggingevent.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/level.h>
#include <log4cxx/helpers/transform.h>
#include <log4cxx/helpers/iso8601dateformat.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/transcoder.h>
#include <log4cxx/ndc.h>
using namespace LOG4CXX_NS;
using namespace LOG4CXX_NS::helpers;
using namespace LOG4CXX_NS::spi;
using namespace LOG4CXX_NS::xml;
struct XMLLayout::XMLLayoutPrivate
{
XMLLayoutPrivate()
: locationInfo(false)
, properties(false)
, expectedPatternLength(100)
{}
// Print no location info by default
bool locationInfo; //= false
bool properties; // = false
// Expected length of a formatted event excluding the message text
size_t expectedPatternLength;
};
IMPLEMENT_LOG4CXX_OBJECT(XMLLayout)
XMLLayout::XMLLayout()
: m_priv(std::make_unique<XMLLayoutPrivate>())
{
m_priv->expectedPatternLength = getFormattedEventCharacterCount() * 2;
}
XMLLayout::~XMLLayout() {}
void XMLLayout::setOption(const LogString& option,
const LogString& value)
{
if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("LOCATIONINFO"), LOG4CXX_STR("locationinfo")))
{
setLocationInfo(OptionConverter::toBoolean(value, false));
m_priv->expectedPatternLength = getFormattedEventCharacterCount() * 2;
}
if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("PROPERTIES"), LOG4CXX_STR("properties")))
{
setProperties(OptionConverter::toBoolean(value, false));
m_priv->expectedPatternLength = getFormattedEventCharacterCount() * 2;
}
}
void XMLLayout::format(LogString& output,
const spi::LoggingEventPtr& event,
Pool& p) const
{
output.reserve(m_priv->expectedPatternLength + event->getMessage().size());
output.append(LOG4CXX_STR("<log4j:event logger=\""));
Transform::appendEscapingTags(output, event->getLoggerName());
output.append(LOG4CXX_STR("\" timestamp=\""));
StringHelper::toString(event->getTimeStamp() / 1000L, p, output);
output.append(LOG4CXX_STR("\" level=\""));
Transform::appendEscapingTags(output, event->getLevel()->toString());
output.append(LOG4CXX_STR("\" thread=\""));
Transform::appendEscapingTags(output, event->getThreadName());
output.append(LOG4CXX_STR("\">"));
output.append(LOG4CXX_EOL);
output.append(LOG4CXX_STR("<log4j:message><![CDATA["));
// Append the rendered message. Also make sure to escape any
// existing CDATA sections.
Transform::appendEscapingCDATA(output, event->getRenderedMessage());
output.append(LOG4CXX_STR("]]></log4j:message>"));
output.append(LOG4CXX_EOL);
LogString ndc;
if (event->getNDC(ndc))
{
output.append(LOG4CXX_STR("<log4j:NDC><![CDATA["));
Transform::appendEscapingCDATA(output, ndc);
output.append(LOG4CXX_STR("]]></log4j:NDC>"));
output.append(LOG4CXX_EOL);
}
if (m_priv->locationInfo)
{
output.append(LOG4CXX_STR("<log4j:locationInfo class=\""));
const LocationInfo& locInfo = event->getLocationInformation();
LOG4CXX_DECODE_CHAR(className, locInfo.getClassName());
Transform::appendEscapingTags(output, className);
output.append(LOG4CXX_STR("\" method=\""));
LOG4CXX_DECODE_CHAR(method, locInfo.getMethodName());
Transform::appendEscapingTags(output, method);
output.append(LOG4CXX_STR("\" file=\""));
LOG4CXX_DECODE_CHAR(fileName, locInfo.getFileName());
Transform::appendEscapingTags(output, fileName);
output.append(LOG4CXX_STR("\" line=\""));
StringHelper::toString(locInfo.getLineNumber(), p, output);
output.append(LOG4CXX_STR("\"/>"));
output.append(LOG4CXX_EOL);
}
if (m_priv->properties)
{
LoggingEvent::KeySet propertySet(event->getPropertyKeySet());
LoggingEvent::KeySet keySet(event->getMDCKeySet());
if (!(keySet.empty() && propertySet.empty()))
{
output.append(LOG4CXX_STR("<log4j:properties>"));
output.append(LOG4CXX_EOL);
for (auto key : keySet)
{
LogString value;
if (event->getMDC(key, value))
{
output.append(LOG4CXX_STR("<log4j:data name=\""));
Transform::appendEscapingTags(output, key);
output.append(LOG4CXX_STR("\" value=\""));
Transform::appendEscapingTags(output, value);
output.append(LOG4CXX_STR("\"/>"));
output.append(LOG4CXX_EOL);
}
}
for (auto key : propertySet)
{
LogString value;
if (event->getProperty(key, value))
{
output.append(LOG4CXX_STR("<log4j:data name=\""));
Transform::appendEscapingTags(output, key);
output.append(LOG4CXX_STR("\" value=\""));
Transform::appendEscapingTags(output, value);
output.append(LOG4CXX_STR("\"/>"));
output.append(LOG4CXX_EOL);
}
}
output.append(LOG4CXX_STR("</log4j:properties>"));
output.append(LOG4CXX_EOL);
}
}
output.append(LOG4CXX_STR("</log4j:event>"));
output.append(LOG4CXX_EOL);
output.append(LOG4CXX_EOL);
}
void XMLLayout::setLocationInfo(bool locationInfo1)
{
m_priv->locationInfo = locationInfo1;
}
bool XMLLayout::getLocationInfo() const
{
return m_priv->locationInfo;
}
void XMLLayout::setProperties(bool flag)
{
m_priv->properties = flag;
}
bool XMLLayout::getProperties()
{
return m_priv->properties;
}