首頁>技術>

OAL 直譯器實現

OAL 直譯器是基於 Antlr4 實現的,我們先來了解下 Antlr4

pom.xml 中配置 antlr4 的依賴和外掛

grammar Calc;   //名稱需要和檔名一致root : expr EOF;   //解決問題: no viable alternative at input '<EOF>'expr    : expr '+' expr     #add   //標籤會生成對應訪問方法方便我們實現呼叫邏輯編寫    | expr '-' expr     #sub    | INT               #int    ;INT : [0-9]+                   //定義整數    ;WS : [ \r\n\t]+ -> skip      //跳過空白類字元   ;

執行一下: mvn compile -Dmaven.test.skip=true ,在 target/generated-sources/antlr4 會生成相應的 Java 程式碼。

使用方式預設是監聽器模式,也可以配置成訪問者模式。

監聽器模式:主要藉助了 ParseTreeWalker 這樣一個類,相當於是一個 hook ,每經過一個樹的節點,便會觸發對應節點的方法。好處就算是比較方便,但是靈活性不夠,不能夠自主性的呼叫任意節點進行使用。

訪問者模式:將每個資料的節點型別高度抽象出來夠,根據你傳入的上下文型別來判斷你想要訪問的是哪個節點,觸發對應的方法

PS:結論,簡單語法監聽器模式就可以了,如果語法比較靈活可以考慮使用訪問者模式。

Antlr4Skywalking 的應用

透過“ Antlr4 基本介紹”一節,基本上對 Antlr4 使用有了個大概的認識。下面來看看 SkywalkingAntlr4 是如何使用的。

詞法定義

oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALLexer.g4 檔案中,我們能看到 OAL 的詞法定義

// Observability Analysis Language lexerlexer grammar OALLexer;@Header {package org.apache.skywalking.oal.rt.grammar;}// KeywordsFROM: 'from';FILTER: 'filter';DISABLE: 'disable';SRC_ALL: 'All';SRC_SERVICE: 'Service';SRC_SERVICE_INSTANCE: 'ServiceInstance';SRC_ENDPOINT: 'Endpoint';SRC_SERVICE_RELATION: 'ServiceRelation';SRC_SERVICE_INSTANCE_RELATION: 'ServiceInstanceRelation';SRC_ENDPOINT_RELATION: 'EndpointRelation';SRC_SERVICE_INSTANCE_JVM_CPU: 'ServiceInstanceJVMCPU';SRC_SERVICE_INSTANCE_JVM_MEMORY: 'ServiceInstanceJVMMemory';SRC_SERVICE_INSTANCE_JVM_MEMORY_POOL: 'ServiceInstanceJVMMemoryPool';SRC_SERVICE_INSTANCE_JVM_GC: 'ServiceInstanceJVMGC';SRC_SERVICE_INSTANCE_JVM_THREAD: 'ServiceInstanceJVMThread';SRC_SERVICE_INSTANCE_JVM_CLASS:'ServiceInstanceJVMClass';SRC_DATABASE_ACCESS: 'DatabaseAccess';SRC_SERVICE_INSTANCE_CLR_CPU: 'ServiceInstanceCLRCPU';SRC_SERVICE_INSTANCE_CLR_GC: 'ServiceInstanceCLRGC';SRC_SERVICE_INSTANCE_CLR_THREAD: 'ServiceInstanceCLRThread';SRC_ENVOY_INSTANCE_METRIC: 'EnvoyInstanceMetric';// Browser keywordsSRC_BROWSER_APP_PERF: 'BrowserAppPerf';SRC_BROWSER_APP_PAGE_PERF: 'BrowserAppPagePerf';SRC_BROWSER_APP_SINGLE_VERSION_PERF: 'BrowserAppSingleVersionPerf';SRC_BROWSER_APP_TRAFFIC: 'BrowserAppTraffic';SRC_BROWSER_APP_PAGE_TRAFFIC: 'BrowserAppPageTraffic';SRC_BROWSER_APP_SINGLE_VERSION_TRAFFIC: 'BrowserAppSingleVersionTraffic';// Constructors symbolsDOT:                                 '.';LR_BRACKET:                          '(';RR_BRACKET:                          ')';LS_BRACKET:                          '[';RS_BRACKET:                          ']';COMMA:                               ',';SEMI:                                ';';EQUAL:                               '=';DUALEQUALS:                          '==';ALL:                                 '*';GREATER:                             '>';LESS:                                '<';GREATER_EQUAL:                       '>=';LESS_EQUAL:                          '<=';NOT_EQUAL:                           '!=';LIKE:                                'like';IN:                                  'in';CONTAIN:                            'contain';NOT_CONTAIN:                        'not contain';// LiteralsBOOL_LITERAL:       'true'            |       'false'            ;NUMBER_LITERAL :   Digits+;CHAR_LITERAL:       '\'' (~['\\\r\n] | EscapeSequence) '\'';STRING_LITERAL:     '"' (~["\\\r\n] | EscapeSequence)* '"';DelimitedComment    : '/*' ( DelimitedComment | . )*? '*/'      -> channel(HIDDEN)    ;LineComment    : '//' ~[\u000A\u000D]*      -> channel(HIDDEN)    ;SPACE:                               [ \t\r\n]+    -> channel(HIDDEN);// IdentifiersIDENTIFIER:         Letter LetterOrDigit*;// Fragment rulesfragment EscapeSequence    : '\\' [btnfr"'\\]    | '\\' ([0-3]? [0-7])? [0-7]    | '\\' 'u'+ HexDigit HexDigit HexDigit HexDigit    ;fragment HexDigits    : HexDigit ((HexDigit | '_')* HexDigit)?    ;fragment HexDigit    : [0-9a-fA-F]    ;fragment Digits    : [0-9] ([0-9_]* [0-9])?    ;fragment LetterOrDigit    : Letter    | [0-9]    ;fragment Letter    : [a-zA-Z$_] // these are the "java letters" below 0x7F    | ~[\u0000-\u007F\uD800-\uDBFF] // covers all characters above 0x7F which are not a surrogate    | [\uD800-\uDBFF] [\uDC00-\uDFFF] // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF    ;
語法定義

oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALParser.g4 檔案中,我們能看到 OAL 的語法定義

parser grammar OALParser;@Header {package org.apache.skywalking.oal.rt.grammar;}options { tokenVocab=OALLexer; }// Top Level Descriptionroot    : (aggregationStatement | disableStatement)*    ;aggregationStatement    : variable (SPACE)? EQUAL (SPACE)? metricStatement DelimitedComment? LineComment? (SEMI|EOF)    ;disableStatement    : DISABLE LR_BRACKET disableSource RR_BRACKET DelimitedComment? LineComment? (SEMI|EOF)    ;metricStatement    : FROM LR_BRACKET source (sourceAttributeStmt+) RR_BRACKET (filterStatement+)? DOT aggregateFunction    ;filterStatement    : DOT FILTER LR_BRACKET filterExpression RR_BRACKET    ;filterExpression    : expression    ;source    : SRC_ALL | SRC_SERVICE | SRC_DATABASE_ACCESS | SRC_SERVICE_INSTANCE | SRC_ENDPOINT |      SRC_SERVICE_RELATION | SRC_SERVICE_INSTANCE_RELATION | SRC_ENDPOINT_RELATION |      SRC_SERVICE_INSTANCE_JVM_CPU | SRC_SERVICE_INSTANCE_JVM_MEMORY | SRC_SERVICE_INSTANCE_JVM_MEMORY_POOL | SRC_SERVICE_INSTANCE_JVM_GC | SRC_SERVICE_INSTANCE_JVM_THREAD | SRC_SERVICE_INSTANCE_JVM_CLASS |// JVM source of service instance      SRC_SERVICE_INSTANCE_CLR_CPU | SRC_SERVICE_INSTANCE_CLR_GC | SRC_SERVICE_INSTANCE_CLR_THREAD |      SRC_ENVOY_INSTANCE_METRIC |      SRC_BROWSER_APP_PERF | SRC_BROWSER_APP_PAGE_PERF | SRC_BROWSER_APP_SINGLE_VERSION_PERF |      SRC_BROWSER_APP_TRAFFIC | SRC_BROWSER_APP_PAGE_TRAFFIC | SRC_BROWSER_APP_SINGLE_VERSION_TRAFFIC    ;disableSource    : IDENTIFIER    ;sourceAttributeStmt    : DOT sourceAttribute    ;sourceAttribute    : IDENTIFIER | ALL    ;variable    : IDENTIFIER    ;aggregateFunction    : functionName LR_BRACKET ((funcParamExpression (COMMA funcParamExpression)?) | (literalExpression (COMMA literalExpression)?))? RR_BRACKET    ;functionName    : IDENTIFIER    ;funcParamExpression    : expression    ;literalExpression    : BOOL_LITERAL | NUMBER_LITERAL | IDENTIFIER    ;expression    : booleanMatch | stringMatch | greaterMatch | lessMatch | greaterEqualMatch | lessEqualMatch | notEqualMatch | booleanNotEqualMatch | likeMatch | inMatch | containMatch | notContainMatch    ;containMatch    : conditionAttributeStmt CONTAIN stringConditionValue    ;notContainMatch    : conditionAttributeStmt NOT_CONTAIN stringConditionValue    ;booleanMatch    : conditionAttributeStmt DUALEQUALS booleanConditionValue    ;stringMatch    :  conditionAttributeStmt DUALEQUALS (stringConditionValue | enumConditionValue)    ;greaterMatch    :  conditionAttributeStmt GREATER numberConditionValue    ;lessMatch    :  conditionAttributeStmt LESS numberConditionValue    ;greaterEqualMatch    :  conditionAttributeStmt GREATER_EQUAL numberConditionValue    ;lessEqualMatch    :  conditionAttributeStmt LESS_EQUAL numberConditionValue    ;booleanNotEqualMatch    :  conditionAttributeStmt NOT_EQUAL booleanConditionValue    ;notEqualMatch    :  conditionAttributeStmt NOT_EQUAL (numberConditionValue | stringConditionValue | enumConditionValue)    ;likeMatch    :  conditionAttributeStmt LIKE stringConditionValue    ;inMatch    :  conditionAttributeStmt IN multiConditionValue    ;multiConditionValue    : LS_BRACKET (numberConditionValue ((COMMA numberConditionValue)*) | stringConditionValue ((COMMA stringConditionValue)*) | enumConditionValue ((COMMA enumConditionValue)*)) RS_BRACKET    ;conditionAttributeStmt    : conditionAttribute ((DOT conditionAttribute)*)    ;conditionAttribute    : IDENTIFIER    ;booleanConditionValue    : BOOL_LITERAL    ;stringConditionValue    : STRING_LITERAL    ;enumConditionValue    : IDENTIFIER DOT IDENTIFIER    ;numberConditionValue    : NUMBER_LITERAL    ;
Antlr4 生成 Java 程式碼

oap-server/oal-grammar 下執行 mvn compile -Dmaven.test.skip=true 會在 oap-server/oal-grammar/target/generated-sources/antlr4 目錄下生成相應的 Java 程式碼

.├── OALLexer.tokens├── OALParser.tokens└── org    └── apache        └── skywalking            └── oal                └── rt                    └── grammar                        ├── OALLexer.interp                        ├── OALLexer.java # 詞法解析器                        ├── OALParser.interp                        ├── OALParser.java # 語法解析器                        ├── OALParserBaseListener.java # 監聽器                        └── OALParserListener.java
Skywalking 的使用

透過“ Antlr4 使用案例”一節,可以知道 Antlr4 有兩種功能實現方式:監聽器或者訪問器。

透過“ Antlr4 生成 Java 程式碼”一節,知道 Skywalking 使用的是監聽器模式。

Skywalking 關於 OAL 的相應的程式碼都在 oap-server/oal-rt 模組中。

org.apache.skywalking.oal.rt.grammar.OALParserBaseListener 的繼承類座標是 org.apache.skywalking.oal.rt.parser.OALListener

package org.apache.skywalking.oal.rt.parser;import java.util.Arrays;import java.util.List;import org.antlr.v4.runtime.misc.NotNull;import org.apache.skywalking.oal.rt.grammar.OALParser;import org.apache.skywalking.oal.rt.grammar.OALParserBaseListener;import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;public class OALListener extends OALParserBaseListener {    private List<AnalysisResult> results;    private AnalysisResult current;    private DisableCollection collection;    private ConditionExpression conditionExpression;    private final String sourcePackage;    public OALListener(OALScripts scripts, String sourcePackage) {        this.results = scripts.getMetricsStmts();        this.collection = scripts.getDisableCollection();        this.sourcePackage = sourcePackage;    }    @Override    public void enterAggregationStatement(@NotNull OALParser.AggregationStatementContext ctx) {        current = new AnalysisResult();    }    @Override    public void exitAggregationStatement(@NotNull OALParser.AggregationStatementContext ctx) {        DeepAnalysis deepAnalysis = new DeepAnalysis();        results.add(deepAnalysis.analysis(current));        current = null;    }    @Override    public void enterSource(OALParser.SourceContext ctx) {        current.setSourceName(ctx.getText());        current.setSourceScopeId(DefaultScopeDefine.valueOf(metricsNameFormat(ctx.getText())));    }    @Override    public void enterSourceAttribute(OALParser.SourceAttributeContext ctx) {        current.getSourceAttribute().add(ctx.getText());    }    @Override    public void enterVariable(OALParser.VariableContext ctx) {    }    @Override    public void exitVariable(OALParser.VariableContext ctx) {        current.setVarName(ctx.getText());        current.setMetricsName(metricsNameFormat(ctx.getText()));        current.setTableName(ctx.getText().toLowerCase());    }    @Override    public void enterFunctionName(OALParser.FunctionNameContext ctx) {        current.setAggregationFunctionName(ctx.getText());    }    @Override    public void enterFilterStatement(OALParser.FilterStatementContext ctx) {        conditionExpression = new ConditionExpression();    }    @Override    public void exitFilterStatement(OALParser.FilterStatementContext ctx) {        current.addFilterExpressionsParserResult(conditionExpression);        conditionExpression = null;    }    @Override    public void enterFuncParamExpression(OALParser.FuncParamExpressionContext ctx) {        conditionExpression = new ConditionExpression();    }    @Override    public void exitFuncParamExpression(OALParser.FuncParamExpressionContext ctx) {        current.addFuncConditionExpression(conditionExpression);        conditionExpression = null;    }    /////////////    // Expression    ////////////    @Override    public void enterConditionAttribute(OALParser.ConditionAttributeContext ctx) {        conditionExpression.getAttributes().add(ctx.getText());    }    @Override    public void enterBooleanMatch(OALParser.BooleanMatchContext ctx) {        conditionExpression.setExpressionType("booleanMatch");    }    @Override    public void enterStringMatch(OALParser.StringMatchContext ctx) {        conditionExpression.setExpressionType("stringMatch");    }    @Override    public void enterGreaterMatch(OALParser.GreaterMatchContext ctx) {        conditionExpression.setExpressionType("greaterMatch");    }    @Override    public void enterGreaterEqualMatch(OALParser.GreaterEqualMatchContext ctx) {        conditionExpression.setExpressionType("greaterEqualMatch");    }    @Override    public void enterLessMatch(OALParser.LessMatchContext ctx) {        conditionExpression.setExpressionType("lessMatch");    }    @Override    public void enterLessEqualMatch(OALParser.LessEqualMatchContext ctx) {        conditionExpression.setExpressionType("lessEqualMatch");    }    @Override    public void enterNotEqualMatch(final OALParser.NotEqualMatchContext ctx) {        conditionExpression.setExpressionType("notEqualMatch");    }    @Override    public void enterBooleanNotEqualMatch(final OALParser.BooleanNotEqualMatchContext ctx) {        conditionExpression.setExpressionType("booleanNotEqualMatch");    }    @Override    public void enterLikeMatch(final OALParser.LikeMatchContext ctx) {        conditionExpression.setExpressionType("likeMatch");    }    @Override    public void enterContainMatch(final OALParser.ContainMatchContext ctx) {        conditionExpression.setExpressionType("containMatch");    }    @Override    public void enterNotContainMatch(final OALParser.NotContainMatchContext ctx) {        conditionExpression.setExpressionType("notContainMatch");    }    @Override    public void enterInMatch(final OALParser.InMatchContext ctx) {        conditionExpression.setExpressionType("inMatch");    }    @Override    public void enterMultiConditionValue(final OALParser.MultiConditionValueContext ctx) {        conditionExpression.enterMultiConditionValue();    }    @Override    public void exitMultiConditionValue(final OALParser.MultiConditionValueContext ctx) {        conditionExpression.exitMultiConditionValue();    }    @Override    public void enterBooleanConditionValue(OALParser.BooleanConditionValueContext ctx) {        enterConditionValue(ctx.getText());    }    @Override    public void enterStringConditionValue(OALParser.StringConditionValueContext ctx) {        enterConditionValue(ctx.getText());    }    @Override    public void enterEnumConditionValue(OALParser.EnumConditionValueContext ctx) {        enterConditionValue(ctx.getText());    }    @Override    public void enterNumberConditionValue(OALParser.NumberConditionValueContext ctx) {        conditionExpression.isNumber();        enterConditionValue(ctx.getText());    }    private void enterConditionValue(String value) {        if (value.split("\\.").length == 2 && !value.startsWith("\"")) {            // Value is an enum.            value = sourcePackage + value;        }        conditionExpression.addValue(value);    }    /////////////    // Expression end.    ////////////    @Override    public void enterLiteralExpression(OALParser.LiteralExpressionContext ctx) {        if (ctx.IDENTIFIER() == null) {            current.addFuncArg(new Argument(EntryMethod.LITERAL_TYPE, Arrays.asList(ctx.getText())));            return;        }        current.addFuncArg(new Argument(EntryMethod.IDENTIFIER_TYPE, Arrays.asList(ctx.getText().split("\\."))));    }    private String metricsNameFormat(String source) {        source = firstLetterUpper(source);        int idx;        while ((idx = source.indexOf("_")) > -1) {            source = source.substring(0, idx) + firstLetterUpper(source.substring(idx + 1));        }        return source;    }    /**     * Disable source     */    @Override    public void enterDisableSource(OALParser.DisableSourceContext ctx) {        collection.add(ctx.getText());    }    private String firstLetterUpper(String source) {        return source.substring(0, 1).toUpperCase() + source.substring(1);    }}

簡單來說,就是透過監聽器封裝了個 org.apache.skywalking.oal.rt.parser.OALScripts 物件

package org.apache.skywalking.oal.rt.parser;import java.util.LinkedList;import java.util.List;import lombok.Getter;@Getterpublic class OALScripts {    // 解析出來的分析結果集合    private List<AnalysisResult> metricsStmts;    // 禁用表示式集合    private DisableCollection disableCollection;    public OALScripts() {        metricsStmts = new LinkedList<>();        disableCollection = new DisableCollection();    }}

org.apache.skywalking.oal.rt.parser.ScriptParser 類讀取 oal 檔案,使用 Antlr 生成的 Java 類進行解析

11
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Discourse 如何設定 Google 的 ads.txt 檔案