我们正在尝试为路由器中生成的日志文件构建解析器。 我们成功构建了它并能够在特定文件中打印有效语言。
但是如果输入根据语法无效,那么我们想在不同的文件中打印它。我们尝试了一些东西但它没有正常工作。 能否请您建议我们这样做的方式?如果可能的话,请给出工作实例。
这是我们尝试过的。
我们没有使用任何特定的IDE,只使用文本编辑器。 vANTLR-4.5
我们的输入:(input.txt)
Dec 24 15:38:13 103.199.144.14 firewall,info NAT: src-nat2 srcnat: in:(none) out:ether1-WAN, proto TCP (SYN), 10.20.114.212:59559->86.96.88.147:6882, len 52
Dec 24 15:38:13 103.199.144.14 firewall,info src-nat2: forward: in:<pppoe-PDR242> out:ether1-WAN, proto TCP (SYN), 10.20.124.8:50055->111.111.111.111:80, len 52
第一行是无效语言。并且不应该通过语法,因此必须打印到failure.txt,但是在success.txt文件中部分打印。
第二行有效,并且在success.txt文件中正确打印,如下面显示的输出文件所示。
输出,我们得到:(success.txt)
Dec 24 15:38:13, 103.199.144.14, .20.114.212, len, 52, , null
Dec 24 15:38:13, 103.199.144.14, pppoe-PDR242, TCP, 10.20.124.8:50055, 111.111.111.111:80, null
语法,我们正在使用:(sys.g)
grammar sys;
r: IDENT NUM time ip x+ user xout proto xuser ipfull xtra ipfull1 xtra1 (xipfull xtra ipfull2 xtra2 xipfull xtra3)*;
time: NUM COLN NUM COLN NUM;
ip: NUM DOT NUM DOT NUM DOT NUM ;
ipfull: NUM DOT NUM DOT NUM DOT NUM COLN NUM ;
ipfull1: NUM DOT NUM DOT NUM DOT NUM COLN NUM ;
ipfull2: NUM DOT NUM DOT NUM DOT NUM COLN NUM ;
xipfull: NUM DOT NUM DOT NUM DOT NUM COLN NUM ;
x: (IDENT | COMMA | COLN | BRAC | HYPHN | NUM)+ LTHAN;
user: (IDENT | HYPHN | DOT | NUM)+ ;
xout: GTHAN IDENT+ COLN IDENT+ HYPHN IDENT+ (DOT IDENT)* COMMA IDENT;
proto: IDENT ;
xuser: (IDENT | BRAC | COMMA)+ ;
xtra: HYPHN GTHAN ;
xtra1: COMMA IDENT (BRAC | NUM);
xtra2: BRAC xtra;
xtra3: COMMA IDENT NUM;
IDENT: ('a'..'z' | 'A'..'Z')('a'..'z' | 'A'..'Z' | '0'..'9')* ;
NUM: ('0'..'9')+ ;
LTHAN: '<' ;
GTHAN: '>' ;
COLN: ':';
COMMA: ',';
BRAC: '(' | ')' ;
HYPHN: '-';
DOT: '.';
WS : (' ' | '\t' | '\r' | '\n')+ -> skip ;
我们的主要课程,我们使用由语法生成的Parser和词法分析器。
import org.antlr.v4.runtime.ANTLRFileStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import java.io.*;
import org.antlr.v4.runtime.*;
public class SysLogCheck {
public static void main(String[] args) throws Exception {
long startTime = System.currentTimeMillis();
BufferedReader br = new BufferedReader(new FileReader("test123.txt"));
String s = null;
//FileWriter out = new FileWriter("abc.txt");
PrintWriter success = new PrintWriter(new FileWriter("success.csv"));
PrintWriter failure = new PrintWriter(new FileWriter("failure.csv"));
while((s=br.readLine())!=null)
{
ANTLRInputStream input = new ANTLRInputStream(s);
sysLexer lexer = new sysLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
sysParser parser = new sysParser(tokens);
ParseTree tree = parser.r();
EvalVisitor visitor = new EvalVisitor();
if((visitor.visit(tree)).equals("failure")) // here visit method of EvalVisitor class returns "failure" then the content should be written
//in failure file and else it should be written in success file
// but this is not working
{
failure.println(s);
}
else
{
success.println(visitor.visit(tree));
}
}
failure.flush();
failure.close();
success.flush();
success.close();
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
System.out.println(elapsedTime);
}
}
我们的EvalVisitor(主要访客类)代码:
import org.antlr.v4.runtime.tree.ParseTree;
import java.io.*;
public class EvalVisitor extends sysBaseVisitor
{
class LogEntry {
String ident1;
String dayNum;
String time;
String ip;
String ipfull;
String user;
String proto;
String ipfull1;
String ipfull2;
String x;
}
static LogEntry logEntry;
@Override
public Object visit(ParseTree tree) {
/* Setup logentry used by all visitors (this case, there is only a single visitor...)*/
logEntry = new LogEntry();
final Object o = super.visit(tree);
//our logic to check whether our input contains "<" or not
if((logEntry.x).contains("<") )
{
return logEntry.ident1 +" " + logEntry.dayNum + " " + logEntry.time+ ", " + logEntry.ip+ ", " + logEntry.user+ ", " + logEntry.proto+ ", " + logEntry.ipfull+ ", " + logEntry.ipfull1+ ", " + logEntry.ipfull2;
}
return "failure"; //else return failure
}
StringBuilder stringBuilder;
@Override
public Object visitR(sysParser.RContext ctx) {
logEntry.ident1 = ctx.IDENT().getText();
logEntry.dayNum = ctx.NUM().getText();
return super.visitR(ctx);
}
@Override
public Object visitTime(sysParser.TimeContext ctx) {
logEntry.time = ctx.getText();
return super.visitTime(ctx);
}
@Override
public Object visitIp(sysParser.IpContext ctx) {
logEntry.ip = ctx.getText();
return super.visitIp(ctx);
}
@Override
public Object visitIpfull(sysParser.IpfullContext ctx) {
logEntry.ipfull = ctx.getText();
return super.visitIpfull(ctx);
}
@Override
public Object visitIpfull1(sysParser.Ipfull1Context ctx) {
logEntry.ipfull1 = ctx.getText();
return super.visitIpfull1(ctx);
}
@Override
public Object visitIpfull2(sysParser.Ipfull2Context ctx) {
logEntry.ipfull2 = ctx.getText();
return super.visitIpfull2(ctx);
}
@Override
public Object visitXipfull(sysParser.XipfullContext ctx) {
return super.visitXipfull(ctx);
}
@Override
public Object visitX(sysParser.XContext ctx) {
logEntry.x = ctx.getText();
return super.visitX(ctx);
}
@Override
public Object visitUser(sysParser.UserContext ctx) {
logEntry.user = ctx.getText();
return super.visitUser(ctx);
}
@Override
public Object visitXuser(sysParser.XuserContext ctx) {
return super.visitXuser(ctx);
}
@Override
public Object visitXout(sysParser.XoutContext ctx) {
return super.visitXout(ctx);
}
@Override
public Object visitProto(sysParser.ProtoContext ctx) {
logEntry.proto = ctx.getText();
return super.visitProto(ctx);
}
@Override
public Object visitXtra(sysParser.XtraContext ctx) {
return super.visitXtra(ctx);
}
@Override
public Object visitXtra1(sysParser.Xtra1Context ctx) {
return super.visitXtra1(ctx);
}
@Override
public Object visitXtra2(sysParser.Xtra2Context ctx) {
return super.visitXtra2(ctx);
}
@Override
public Object visitXtra3(sysParser.Xtra3Context ctx) {
return super.visitXtra3(ctx);
}
}
答案 0 :(得分:1)
如果您要做的只是创建一个包含您认为有效行的数据的文件,那么ANTLR可能有点过分(我在邮件列表线程中提到过这一点)。我在这里假设你可能想要对解析后的结果做更多的事情(或者你只是真的想要使用ANTLR)
我看到你已经分别解析了每个输入行。
您的'r'解析器规则似乎识别有效行和“无效”行。我建议收紧语法来定义你认为有效的行。如果您的语法只接受(即“识别”)有效行,则任何无效行都将抛出RecognitionException。
您没有提及第2行有效且第1行无效的内容,因此我无法真正就如何更正“r”规则提出建议。
(关于你的语法有很多批评,它表明你正在努力学习“足够的”ANTLR。我不认为你要求对你的语法进行全面批评,所以我会跳过细节。)
检查完代码后,您似乎只想识别特定类型的日志行,并从这些行中捕获数据。 如果这是您要完成的任务,那么请查看Java正则表达式和捕获组。它比使用ANTLR要简单得多(而且我是ANTLR的忠实粉丝)。