Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LOGCXX-559 Implement the LocationInfoFilter #171

Merged
merged 2 commits into from
Dec 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ target_sources(log4cxx
loader.cpp
locale.cpp
locationinfo.cpp
locationinfofilter.cpp
logger.cpp
loggermatchfilter.cpp
loggerpatternconverter.cpp
Expand Down
2 changes: 2 additions & 0 deletions src/main/cpp/class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include <log4cxx/filter/levelmatchfilter.h>
#include <log4cxx/filter/levelrangefilter.h>
#include <log4cxx/filter/stringmatchfilter.h>
#include <log4cxx/filter/locationinfofilter.h>
#include <log4cxx/rolling/filterbasedtriggeringpolicy.h>
#include <log4cxx/rolling/fixedwindowrollingpolicy.h>
#include <log4cxx/rolling/manualtriggeringpolicy.h>
Expand Down Expand Up @@ -178,6 +179,7 @@ void Class::registerClasses()
LevelMatchFilter::registerClass();
LevelRangeFilter::registerClass();
StringMatchFilter::registerClass();
LocationInfoFilter::registerClass();
log4cxx::rolling::RollingFileAppender::registerClass();
log4cxx::rolling::SizeBasedTriggeringPolicy::registerClass();
log4cxx::rolling::TimeBasedRollingPolicy::registerClass();
Expand Down
138 changes: 138 additions & 0 deletions src/main/cpp/locationinfofilter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* 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/filter/locationinfofilter.h>
#include <log4cxx/spi/loggingevent.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/optionconverter.h>
#include <log4cxx/private/filter_priv.h>
#include <log4cxx/helpers/loglog.h>

using namespace log4cxx;
using namespace log4cxx::filter;
using namespace log4cxx::spi;
using namespace log4cxx::helpers;

#define priv static_cast<LocationInfoFilterPrivate*>(m_priv.get())

struct LocationInfoFilter::LocationInfoFilterPrivate : public FilterPrivate
{
LocationInfoFilterPrivate() : FilterPrivate(),
acceptOnMatch(true),
mustMatchAll(false),
lineNumber(-1)
{}

bool acceptOnMatch;
bool mustMatchAll; // true = AND; false = OR
int lineNumber;
LogString methodName;
};

IMPLEMENT_LOG4CXX_OBJECT(LocationInfoFilter)

LocationInfoFilter::LocationInfoFilter() :
Filter(std::make_unique<LocationInfoFilterPrivate>())
{
}

LocationInfoFilter::~LocationInfoFilter() {}

void LocationInfoFilter::setOption( const LogString& option,
const LogString& value)
{
LogLog::warn(option + ":" + value);
if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("ACCEPTONMATCH"), LOG4CXX_STR("acceptonmatch")))
{
priv->acceptOnMatch = OptionConverter::toBoolean(value, priv->acceptOnMatch);
}
else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("OPERATOR"), LOG4CXX_STR("operator")))
{
priv->mustMatchAll = StringHelper::equalsIgnoreCase(value, LOG4CXX_STR("AND"), LOG4CXX_STR("and")) ? true : false;
}
else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("LINENUMBER"), LOG4CXX_STR("linenumber")))
{
priv->lineNumber = OptionConverter::toInt(value, -1);
}
else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("METHOD"), LOG4CXX_STR("method")))
{
priv->methodName = value;
}
}

Filter::FilterDecision LocationInfoFilter::decide(
const log4cxx::spi::LoggingEventPtr& event) const
{
if (priv->lineNumber == -1 &&
priv->methodName.empty())
{
return Filter::NEUTRAL;
}

if (event->getLocationInformation().getLineNumber() == -1 ||
event->getLocationInformation().getMethodName().compare(LocationInfo::NA_METHOD) == 0){
return Filter::NEUTRAL;
}

bool matched = false;
bool matchLineNumber = priv->lineNumber == event->getLocationInformation().getLineNumber();
bool matchMethodName = priv->methodName.compare(event->getLocationInformation().getMethodName()) == 0;

if(priv->mustMatchAll){
matched = matchLineNumber && matchMethodName;
}else{
matched = matchLineNumber || matchMethodName;
}

if (priv->acceptOnMatch)
{
return matched ? Filter::ACCEPT : Filter::NEUTRAL;
}
else
{
return matched ? Filter::DENY : Filter::NEUTRAL;
}
}

void LocationInfoFilter::setAcceptOnMatch(bool acceptOnMatch1)
{
priv->acceptOnMatch = acceptOnMatch1;
}

bool LocationInfoFilter::getAcceptOnMatch() const
{
return priv->acceptOnMatch;
}

bool LocationInfoFilter::getMustMatchAll() const
{
return priv->mustMatchAll;
}

void LocationInfoFilter::setMustMatchAll(bool mustMatchAll1)
{
priv->mustMatchAll = mustMatchAll1;
}

void LocationInfoFilter::setLineNumber(int lineNum){
priv->lineNumber = lineNum;
}

void LocationInfoFilter::setMethodName(const LogString& methodName){
priv->methodName = methodName;
}
53 changes: 26 additions & 27 deletions src/main/include/log4cxx/filter/locationinfofilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,54 +21,50 @@

namespace log4cxx
{
namespace rule
{
class ExpressionRule;
class Rule;
typedef helpers::ObjectPtrT < Rule > RulePtr;
typedef helpers::ObjectPtrT < ExpressionRule > ExpressionRulePtr;
}

namespace filter
{

/**
* Location information is usually specified at the appender level - all events associated
* with an appender either create and parse stack traces or they do not. This is
* an expensive operation and in some cases not needed for all events associated with
* an appender.
* When location information is available, individual log statements can be turned on or off
* depending on their source location.
*
* This filter creates event-level location information only if the provided expression evaluates to true.
*
* For information on expression syntax, see org.apache.log4j.rule.ExpressionRule
* This filter allows for filtering messages based off of either the line number of the
* message, or the name of the method that the log mesage is in. The 'operator' parameter
* may be used to determine if both the method name and line number must match.
* If 'operator' is set to 'AND', then both the line number and method name must match,
* otherwise only one needs to match. By default, 'operator' is set to 'OR'.
*
* If location information is not available, this filter does nothing.
*
*/
class LOG4CXX_EXPORT LocationInfoFilter: public log4cxx::spi::Filter
{
bool convertInFixToPostFix;
LOG4CXX_DECLARE_PRIVATE_MEMBER(LogString, expression)
LOG4CXX_DECLARE_PRIVATE_MEMBER(rule::RulePtr, expressionRule)
//HACK: Category is the last of the internal layers - pass this in as the class name
//in order for parsing to work correctly
LogString className;

struct LocationInfoFilterPrivate;
public:
DECLARE_LOG4CXX_OBJECT(LocationInfoFilter)
BEGIN_LOG4CXX_CAST_MAP()
LOG4CXX_CAST_ENTRY(log4cxx::spi::Filter)
LOG4CXX_CAST_ENTRY(LocationInfoFilter)
LOG4CXX_CAST_ENTRY_CHAIN(log4cxx::spi::Filter)
END_LOG4CXX_CAST_MAP()

LocationInfoFilter();

void activateOptions(helpers::Pool&) override;
~LocationInfoFilter();

void setExpression(const LogString& expression);
void setOption(const LogString& option, const LogString& value) override;

LogString getExpression() const;
void setLineNumber(int lineNum);

void setConvertInFixToPostFix(bool convertInFixToPostFix);
void setMethodName(const LogString& methodName);

bool getConvertInFixToPostFix() const;
void setAcceptOnMatch(bool acceptOnMatch1);

bool getAcceptOnMatch() const;

bool getMustMatchAll() const;

void setMustMatchAll(bool mustMatchAll1);

/**
* If this event does not already contain location information,
Expand All @@ -82,6 +78,9 @@ class LOG4CXX_EXPORT LocationInfoFilter: public log4cxx::spi::Filter
FilterDecision decide(const spi::LoggingEventPtr& event) const override;

};

LOG4CXX_PTR_DEF(LocationInfoFilter);

}
}
#endif
4 changes: 3 additions & 1 deletion src/main/include/log4cxx/patternlayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ LOG4CXX_LIST_DEF(FormattingInfoList, log4cxx::pattern::FormattingInfoPtr);
* <p>
* Let the conversion pattern be <strong>"%-5p [%t]: %m%n"</strong> and assume that the log4cxx
* environment was set to use a PatternLayout. Then the statements
* ~~~{.cpp}
*
* ~~~{.cpp}
* auto root = Logger::getRootLogger();
* root->debug("Message 1");
* root->warn("Message 2");
* ~~~
*
* would yield the output
* <pre>
* DEBUG [main]: Message 1
Expand Down
2 changes: 1 addition & 1 deletion src/site/markdown/1-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ Usage {#usage-overview}
See the following pages for usage information:

* @subpage usage
* @subpage filters
* @subpage threading
* @subpage extending-log4cxx
* @subpage faq
* @subpage configuration-samples
* @subpage qt-support
* @subpage performance
* @subpage map-filter
* @subpage multiprocess-logging
* @subpage environment-variables
* @subpage macros-influencing-log4cxx
74 changes: 74 additions & 0 deletions src/site/markdown/filters/LocationInfoFilter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
LocationInfoFilter {#location-info-filter}
===
<!--
Note: License header cannot be first, as doxygen does not generate
cleanly if it before the '==='
-->
<!--
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.
-->

The LocationInfoFilter allows filtering against the location in the file that
the log statement was made. Location information must not be disabled in order
for this filter to be effective. Location information is disabled with the
`LOG4CXX_DISABLE_LOCATION_INFO` macro.

| **Parameter Name** | **Type** | **Description** |
|:-------------------|:----------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Operator | LogString | If the operator is `AND` then all the parts of the location(line number and method name) must match. If set to `OR` then only one needs to match. The default value is `OR`. |
| AcceptOnMatch | bool | If `true`, accept the message when it matches the parameters. If `false`, deny the message when it matches the parameters. |
| LineNumber | int | The line number to match on. The default line number is -1. |
| Method | LogString | The method to match on. The method name may be compiler-specific. On GCC, the method name will look like `Class::methodName` |

Assume that our code looks something like the following:

~~~{.cpp}
LOG4CXX_TRACE(logger, "About to do something!");
for( int x = 0; x < 100; x++ ){
LOG4CXX_TRACE(logger, "Do something number " << x);
}
~~~

For various reasons, we may want to know that we are about to do something, but
we don't want to know each iteration of the loop. In order to filter out this
one message we can create a LocationInfoFilter in order to specifiy the line
number that this message is on in order to filter it out:

~~~{.xml}
<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration xmlns:log4j="http://logging.apache.org/">
<appender name="SIMPLE" class="ConsoleAppender">
<param name="Target" value="System.err"/>

<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%p - %m%n"/>
</layout>

<filter class="LocationInfoFilter">
<param name="LineNumber" value="182" />
<param name="Operator" value="OR" />
<param name="AcceptOnMatch" value="false" />
</filter>
</appender>
<root>
<priority value="all" />
<appender-ref ref="SIMPLE" />
</root>
</log4j:configuration>
~~~

Doing this allows us to still see the "About to do something!" message, but
ignore each iteration of the loop.
Loading