.NET NLog 详解(五) - Condition Expression
2024-10-19 06:20:02
Sample
<!-- during normal execution only log Info messages -->
<defaultFilter>level >= LogLevel.Info</defaultFilter>
<!-- if there is at least one error, log everything from trace level -->
<when exists="level >= LogLevel.Error" filter="level >= LogLevel.Trace" />
实现将字符串转换成表达式进行逻辑判断,然后做出相应的动作。这个过程的实现使用Condition Expression。
从简单的例子开始:
public void BooleanOperatorTest()
{
AssertEvaluationResult(false, "false or false");
AssertEvaluationResult(true, "false or true");
AssertEvaluationResult(true, "true or false");
AssertEvaluationResult(true, "true or true");
AssertEvaluationResult(false, "false and false");
AssertEvaluationResult(false, "false and true");
AssertEvaluationResult(false, "true and false");
AssertEvaluationResult(true, "true and true");
AssertEvaluationResult(false, "not true");
AssertEvaluationResult(true, "not false");
AssertEvaluationResult(false, "not not false");
AssertEvaluationResult(true, "not not true");
}
输入的是字符串false or false
,我们希望的结果是得到false
,大概的过程是这样的:
CondtionParser
/// <summary>
/// Condition parser. Turns a string representation of condition expression
/// into an expression tree.
/// </summary>
public class ConditionParser
第一步就是初始化这个Parser
var parser = new ConditionParser(new SimpleStringReader(expressionText), configurationItemFactories);
顺带初始化了tokenizer
private ConditionParser(SimpleStringReader stringReader, ConfigurationItemFactory configurationItemFactory)
{
this.configurationItemFactory = configurationItemFactory;
this.tokenizer = new ConditionTokenizer(stringReader);
}
构造函数里直接取到了第一个token false
public ConditionTokenizer(SimpleStringReader stringReader)
{
this.stringReader = stringReader;
this.TokenType = ConditionTokenType.BeginningOfInput;
this.GetNextToken();
}
获取的过程也比较的简单,一个接一个的读入char,
遇到非指定的字符即停止
private void ParseKeyword(char ch)
{
int i;
this.TokenType = ConditionTokenType.Keyword;
StringBuilder sb = new StringBuilder();
sb.Append((char)ch);
this.ReadChar();
while ((i = this.PeekChar()) != -1)
{
if ((char)i == '_' || (char)i == '-' || char.IsLetterOrDigit((char)i))
{
sb.Append((char)this.ReadChar());
}
else
{
break;
}
}
this.TokenValue = sb.ToString();
}
这里有一系列比较复杂的表达式树生成的过程:
private ConditionExpression ParseBooleanOr()
{
ConditionExpression expression = this.ParseBooleanAnd();
while (this.tokenizer.IsKeyword("or") || this.tokenizer.IsToken(ConditionTokenType.Or))
{
this.tokenizer.GetNextToken();
expression = new ConditionOrExpression(expression, this.ParseBooleanAnd());
}
return expression;
}
最后拿到的表达式树是这样的:
左右的表达式为ConditionLiteralExpression
。
private ConditionExpression ParseLiteralExpression()
{
//......
if (this.tokenizer.TokenType == ConditionTokenType.Keyword)
{
string keyword = this.tokenizer.EatKeyword();
if (0 == string.Compare(keyword, "level", StringComparison.OrdinalIgnoreCase))
{
return new ConditionLevelExpression();
}
if (0 == string.Compare(keyword, "logger", StringComparison.OrdinalIgnoreCase))
{
return new ConditionLoggerNameExpression();
}
if (0 == string.Compare(keyword, "message", StringComparison.OrdinalIgnoreCase))
{
return new ConditionMessageExpression();
}
if (0 == string.Compare(keyword, "loglevel", StringComparison.OrdinalIgnoreCase))
{
this.tokenizer.Expect(ConditionTokenType.Dot);
return new ConditionLiteralExpression(LogLevel.FromString(this.tokenizer.EatKeyword()));
}
if (0 == string.Compare(keyword, "true", StringComparison.OrdinalIgnoreCase))
{
return new ConditionLiteralExpression(true);
}
再来个例子:
public void ConditionMethodsTest()
{
AssertEvaluationResult(true, "starts-with('foobar','foo')");
AssertEvaluationResult(false, "starts-with('foobar','bar')");
AssertEvaluationResult(true, "ends-with('foobar','bar')");
AssertEvaluationResult(false, "ends-with('foobar','foo')");
AssertEvaluationResult(0, "length('')");
AssertEvaluationResult(4, "length('${level}')");
AssertEvaluationResult(false, "equals(1, 2)");
AssertEvaluationResult(true, "equals(3.14, 3.14)");
AssertEvaluationResult(true, "contains('foobar','ooba')");
AssertEvaluationResult(false, "contains('foobar','oobe')");
AssertEvaluationResult(false, "contains('','foo')");
AssertEvaluationResult(true, "contains('foo','')");
}
这里出现了一些条件方法starts-with
,ends-with
,equals
,contains
,可以通过这些操作,当log的message包含特定的字符串的时候才写日志
[ConditionMethod("starts-with")]
是以属性反射的方式在初始化的时候加载的。
在parse的过程中,多一步判断是否是ConditionMethods并创建实例
private ConditionMethodExpression ParsePredicate(string functionName)
{
try
{
var methodInfo = this.configurationItemFactory.ConditionMethods.CreateInstance(functionName);
return new ConditionMethodExpression(functionName, methodInfo, par);
}
catch (Exception exception)
{
if (exception.MustBeRethrown())
{
throw;
}
throw new ConditionParseException("Cannot resolve function '" + functionName + "'", exception);
}
}
那么怎么知道该字符串是否是ConditionMethods呢?这里还是简单从左到右一个个的吃字符。
public string EatKeyword()
{
if (this.TokenType != ConditionTokenType.Keyword)
{
throw new ConditionParseException("Identifier expected");
}
string s = (string)this.TokenValue;
this.GetNextToken();
return s;
}
当出现特殊的char时候做出判断。
private static ConditionTokenType[] BuildCharIndexToTokenType()
{
CharToTokenType[] charToTokenType =
{
new CharToTokenType('(', ConditionTokenType.LeftParen),
new CharToTokenType(')', ConditionTokenType.RightParen),
new CharToTokenType('.', ConditionTokenType.Dot),
new CharToTokenType(',', ConditionTokenType.Comma),
new CharToTokenType('!', ConditionTokenType.Not),
new CharToTokenType('-', ConditionTokenType.Minus),
};
最新文章
- python之类介绍
- 基于HTML5的Drag and Drop生成图片Base64信息
- Greedy:Stall Reservations(POJ 3190)
- 双系统重装windows后修复UBUNTU的GRUB
- 推荐:一个个人开发者搞app赚钱之后的总结!有图有真相。
- [译]GotW #6a: Const-Correctness, Part 1
- java特点
- Android中的TextView实现多行显示省略号
- 你知道OneNote的OCR功能吗?office lens为其增大威力,中文也识别
- LoonAndroid自动检测输入框 --- Author: rose &;&; lvyerose@163.com
- Js中有关变量声明和函数声明提升的问题
- Python中的引号用法总结
- K - 迷宫问题 POJ - 3984
- Spring(四):Spring整合Hibernate,之后整合Struts2
- POE 供电
- mysql varchar存储最大
- 15款css3鼠标悬停图片动画过渡特效
- golang 的 buffered channel 及 unbuffered channel
- grafana + influxdb + telegraf
- golang爬取免费代理IP
热门文章
- nginx 下 bootstrap fa 字体异常问题
- dtw算法
- 【Networking】flannel,pipework,weave,udp,vxlan,ovs等资料
- 【GoLang】GoLang for 中有多个循环变量怎么处理?
- C#系统委托之Action And Func
- Delphi 多步操作产生错误,请检查每一步的状态值
- WinAPI: ShellExecute - 打开外部程序或文件
- Greedy:Bound Found(POJ 2566)
- CSS3实现圆角效果
- IOS - NSURLSession