You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2019/07/18 06:49:22 UTC

[skywalking] 05/13: Finish metrics generation.

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch rt-oal
in repository https://gitbox.apache.org/repos/asf/skywalking.git

commit cf098be65cc8c5a30bddb0831f882410677fe392
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Wed Jul 17 15:30:52 2019 +0800

    Finish metrics generation.
---
 .../org/apache/skywalking/oal/rt/OALRuntime.java   | 132 +++++++++++++++++----
 .../code-templates/metrics-builder/data2Map.ftl    |  30 +++++
 .../code-templates/metrics-builder/map2Data.ftl    |  22 ++++
 3 files changed, 161 insertions(+), 23 deletions(-)

diff --git a/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/OALRuntime.java b/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/OALRuntime.java
index e2a2426..d4f5268 100644
--- a/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/OALRuntime.java
+++ b/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/OALRuntime.java
@@ -20,10 +20,11 @@ package org.apache.skywalking.oal.rt;
 
 import freemarker.template.Configuration;
 import freemarker.template.Version;
+import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.PrintWriter;
 import java.io.Reader;
 import java.io.StringWriter;
 import java.nio.charset.Charset;
@@ -40,12 +41,12 @@ import javassist.CtNewMethod;
 import javassist.NotFoundException;
 import javassist.bytecode.AnnotationsAttribute;
 import javassist.bytecode.ClassFile;
-import javassist.bytecode.ClassFilePrinter;
 import javassist.bytecode.ConstPool;
 import javassist.bytecode.annotation.Annotation;
 import javassist.bytecode.annotation.ClassMemberValue;
 import javassist.bytecode.annotation.IntegerMemberValue;
 import javassist.bytecode.annotation.StringMemberValue;
+import org.apache.commons.io.FileUtils;
 import org.apache.skywalking.oal.rt.meta.MetaReader;
 import org.apache.skywalking.oal.rt.meta.MetaSettings;
 import org.apache.skywalking.oal.rt.output.AllDispatcherContext;
@@ -82,9 +83,13 @@ public class OALRuntime implements OALEngine {
     private static final String DYNAMIC_METRICS_CLASS_PACKAGE = "org.apache.skywalking.oal.rt.metrics.";
     private static final String DYNAMIC_METRICS_BUILDER_CLASS_PACKAGE = "org.apache.skywalking.oal.rt.metrics.builder";
     private static final String WITH_METADATA_INTERFACE = "org.apache.skywalking.oap.server.core.analysis.metrics.WithMetadata";
+    private static final String STORAGE_BUILDER_INTERFACE = "org.apache.skywalking.oap.server.core.storage.StorageBuilder";
+    private static final String SOURCE_DISPATCHER_INTERFACE = "org.apache.skywalking.oap.server.core.analysis.SourceDispatcher";
     private static final String METRICS_STREAM_PROCESSOR = "org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor";
     private static final String[] METRICS_CLASS_METHODS =
         {"id", "hashCode", "remoteHashCode", "equals", "serialize", "deserialize", "getMeta", "toDay"};
+    private static final String[] METRICS_BUILDER_CLASS_METHODS =
+        {"data2Map", "map2Data"};
     private final ClassPool classPool;
     private ClassLoader currentClassLoader;
     private Configuration configuration;
@@ -106,6 +111,8 @@ public class OALRuntime implements OALEngine {
     }
 
     @Override public void start(ClassLoader currentClassLoader) throws ModuleStartException, OALCompileException {
+        prepareRTTempFoler();
+
         this.currentClassLoader = currentClassLoader;
         Reader read;
         try {
@@ -156,19 +163,27 @@ public class OALRuntime implements OALEngine {
 
     }
 
+    /**
+     * Generate metrics class, and inject it to classloader
+     *
+     * @param metricsStmt
+     * @return
+     * @throws OALCompileException
+     */
     private Class generateMetricsClass(AnalysisResult metricsStmt) throws OALCompileException {
+        String className = metricsClassName(metricsStmt, false);
         CtClass parentMetricsClass = null;
         try {
             parentMetricsClass = classPool.get(METRICS_FUNCTION_PACKAGE + metricsStmt.getMetricsClassName());
         } catch (NotFoundException e) {
-            logger.error("Can't find parent class for " + metricsStmt.getMetricsName() + ".", e);
+            logger.error("Can't find parent class for " + className + ".", e);
             throw new OALCompileException(e.getMessage(), e);
         }
-        CtClass metricsClass = classPool.makeClass(metricsClassName(metricsStmt), parentMetricsClass);
+        CtClass metricsClass = classPool.makeClass(metricsClassName(metricsStmt, true), parentMetricsClass);
         try {
             metricsClass.addInterface(classPool.get(WITH_METADATA_INTERFACE));
         } catch (NotFoundException e) {
-            logger.error("Can't find WithMetadata interface for " + metricsStmt.getMetricsName() + ".", e);
+            logger.error("Can't find WithMetadata interface for " + className + ".", e);
             throw new OALCompileException(e.getMessage(), e);
         }
 
@@ -179,10 +194,10 @@ public class OALRuntime implements OALEngine {
          * Create empty construct
          */
         try {
-            CtConstructor defaultConstructor = CtNewConstructor.make("public " + metricsStmt.getMetricsName() + "Metrics() {}", metricsClass);
+            CtConstructor defaultConstructor = CtNewConstructor.make("public " + className + "() {}", metricsClass);
             metricsClass.addConstructor(defaultConstructor);
         } catch (CannotCompileException e) {
-            logger.error("Can't add empty constructor in " + metricsStmt.getMetricsName() + ".", e);
+            logger.error("Can't add empty constructor in " + className + ".", e);
             throw new OALCompileException(e.getMessage(), e);
         }
 
@@ -219,7 +234,7 @@ public class OALRuntime implements OALEngine {
                 newField.getFieldInfo().addAttribute(annotationsAttribute);
 
             } catch (CannotCompileException e) {
-                logger.error("Can't add field(including set/get) " + field.getFieldName() + " in " + metricsStmt.getMetricsName() + ".", e);
+                logger.error("Can't add field(including set/get) " + field.getFieldName() + " in " + className + ".", e);
                 throw new OALCompileException(e.getMessage(), e);
             }
         }
@@ -233,7 +248,7 @@ public class OALRuntime implements OALEngine {
                 configuration.getTemplate("metrics/" + method + ".ftl").process(metricsStmt, methodEntity);
                 metricsClass.addMethod(CtNewMethod.make(methodEntity.toString(), metricsClass));
             } catch (Exception e) {
-                logger.error("Can't generate method " + method + " for " + metricsStmt.getMetricsName() + ".", e);
+                logger.error("Can't generate method " + method + " for " + className + ".", e);
                 throw new OALCompileException(e.getMessage(), e);
             }
         }
@@ -247,7 +262,7 @@ public class OALRuntime implements OALEngine {
         Annotation streamAnnotation = new Annotation(Stream.class.getName(), constPool);
         streamAnnotation.addMemberValue("name", new StringMemberValue(metricsStmt.getTableName(), constPool));
         streamAnnotation.addMemberValue("scopeId", new IntegerMemberValue(constPool, metricsStmt.getSourceScopeId()));
-        streamAnnotation.addMemberValue("builder", new ClassMemberValue(metricsBuilderClassName(metricsStmt), constPool));
+        streamAnnotation.addMemberValue("builder", new ClassMemberValue(metricsBuilderClassName(metricsStmt, true), constPool));
         streamAnnotation.addMemberValue("processor", new ClassMemberValue(METRICS_STREAM_PROCESSOR, constPool));
 
         annotationsAttribute.addAnnotation(streamAnnotation);
@@ -257,26 +272,76 @@ public class OALRuntime implements OALEngine {
         try {
             targetClass = metricsClass.toClass(currentClassLoader, null);
         } catch (CannotCompileException e) {
-            logger.error("Can't compile/load " + metricsStmt.getMetricsName() + ".", e);
+            logger.error("Can't compile/load " + className + ".", e);
             throw new OALCompileException(e.getMessage(), e);
         }
 
         logger.debug("Generate metrics class, " + metricsClass.getName());
-        writeGeneratedFile(metricsClassClassFile, metricsClass.getSimpleName());
+        writeGeneratedFile(metricsClass, metricsClass.getSimpleName(), "metrics");
 
         return targetClass;
     }
 
+    /**
+     * Generate metrics class builder and inject it to classloader
+     *
+     * @param metricsStmt
+     * @throws OALCompileException
+     */
     private void generateMetricsBuilderClass(AnalysisResult metricsStmt) throws OALCompileException {
+        String className = metricsBuilderClassName(metricsStmt, false);
+        CtClass metricsBuilderClass = classPool.makeClass(metricsBuilderClassName(metricsStmt, true));
+        try {
+            metricsBuilderClass.addInterface(classPool.get(STORAGE_BUILDER_INTERFACE));
+        } catch (NotFoundException e) {
+            logger.error("Can't find StorageBuilder interface for " + className + ".", e);
+            throw new OALCompileException(e.getMessage(), e);
+        }
+
+        ClassFile metricsClassClassFile = metricsBuilderClass.getClassFile();
+        ConstPool constPool = metricsClassClassFile.getConstPool();
+
+        /**
+         * Create empty construct
+         */
+        try {
+            CtConstructor defaultConstructor = CtNewConstructor.make("public " + className + "() {}", metricsBuilderClass);
+            metricsBuilderClass.addConstructor(defaultConstructor);
+        } catch (CannotCompileException e) {
+            logger.error("Can't add empty constructor in " + className + ".", e);
+            throw new OALCompileException(e.getMessage(), e);
+        }
+
+        /**
+         * Generate methods
+         */
+        for (String method : METRICS_BUILDER_CLASS_METHODS) {
+            StringWriter methodEntity = new StringWriter();
+            try {
+                configuration.getTemplate("metrics-builder/" + method + ".ftl").process(metricsStmt, methodEntity);
+                metricsBuilderClass.addMethod(CtNewMethod.make(methodEntity.toString(), metricsBuilderClass));
+            } catch (Exception e) {
+                logger.error("Can't generate method " + method + " for " + className + ".", e);
+                throw new OALCompileException(e.getMessage(), e);
+            }
+        }
+
+        try {
+            metricsBuilderClass.toClass(currentClassLoader, null);
+        } catch (CannotCompileException e) {
+            logger.error("Can't compile/load " + className + ".", e);
+            throw new OALCompileException(e.getMessage(), e);
+        }
 
+        writeGeneratedFile(metricsBuilderClass, className, "metrics/builder");
     }
 
-    private String metricsClassName(AnalysisResult metricsStmt) {
-        return DYNAMIC_METRICS_CLASS_PACKAGE + metricsStmt.getMetricsName() + "Metrics";
+    private String metricsClassName(AnalysisResult metricsStmt, boolean fullName) {
+        return (fullName ? DYNAMIC_METRICS_CLASS_PACKAGE : "") + metricsStmt.getMetricsName() + "Metrics";
     }
 
-    private String metricsBuilderClassName(AnalysisResult metricsStmt) {
-        return DYNAMIC_METRICS_BUILDER_CLASS_PACKAGE + metricsStmt.getMetricsName() + "MetricsBuilder";
+    private String metricsBuilderClassName(AnalysisResult metricsStmt, boolean fullName) {
+        return (fullName ? DYNAMIC_METRICS_BUILDER_CLASS_PACKAGE : "") + metricsStmt.getMetricsName() + "MetricsBuilder";
     }
 
     private void buildDispatcherContext(AnalysisResult metricsStmt) {
@@ -292,28 +357,49 @@ public class OALRuntime implements OALEngine {
         context.getMetrics().add(metricsStmt);
     }
 
-    private void writeGeneratedFile(ClassFile metricsClassClassFile, String className) throws OALCompileException {
-        PrintWriter printWriter = null;
+    private void prepareRTTempFoler() {
+        File workPath = WorkPath.getPath();
+        File folder = new File(workPath.getParentFile(), "oal-rt/");
+        if (folder.exists()) {
+            try {
+                FileUtils.deleteDirectory(folder);
+            } catch (IOException e) {
+                logger.warn("Can't delete " + folder.getAbsolutePath() + " temp folder.", e);
+            }
+        }
+        folder.mkdirs();
+    }
+
+    private void writeGeneratedFile(CtClass metricsClass, String className, String type) throws OALCompileException {
+        DataOutputStream printWriter = null;
         try {
             File workPath = WorkPath.getPath();
-            File folder = new File(workPath.getParentFile(), "oal-rt");
+            File folder = new File(workPath.getParentFile(), "oal-rt/" + type);
             if (!folder.exists()) {
                 folder.mkdirs();
             }
-            File file = new File(folder, className + ".txt");
+            File file = new File(folder, className + ".class");
             if (file.exists()) {
                 file.delete();
             }
             file.createNewFile();
-            printWriter = new PrintWriter(file);
-            ClassFilePrinter.print(metricsClassClassFile, printWriter);
+
+            printWriter = new DataOutputStream(new FileOutputStream(file));
+            metricsClass.toBytecode(printWriter);
             printWriter.flush();
         } catch (IOException e) {
             logger.warn("Can't create " + className + ".txt, ignore.", e);
             return;
+        } catch (CannotCompileException e) {
+            logger.warn("Can't compile " + className + ".class(should not happen), ignore.", e);
+            return;
         } finally {
             if (printWriter != null) {
-                printWriter.close();
+                try {
+                    printWriter.close();
+                } catch (IOException e) {
+
+                }
             }
         }
 
diff --git a/oap-server/oal-rt/src/main/resources/code-templates/metrics-builder/data2Map.ftl b/oap-server/oal-rt/src/main/resources/code-templates/metrics-builder/data2Map.ftl
new file mode 100644
index 0000000..1ee5df5
--- /dev/null
+++ b/oap-server/oal-rt/src/main/resources/code-templates/metrics-builder/data2Map.ftl
@@ -0,0 +1,30 @@
+public java.util.Map data2Map(org.apache.skywalking.oal.rt.metrics.${metricsName}Metrics storageData) {
+    java.util.Map map = new java.util.HashMap();
+    <#list fieldsFromSource as field>
+        <#if field.typeName == "long">
+            map.put((Object)"${field.columnName}", new Long(storageData.${field.fieldGetter}()));
+        <#elseif field.typeName == "int">
+            map.put((Object)"${field.columnName}", new Integer(storageData.${field.fieldGetter}()));
+        <#elseif field.typeName == "double">
+            map.put((Object)"${field.columnName}", new Double(storageData.${field.fieldGetter}()));
+        <#elseif field.typeName == "float">
+            map.put((Object)"${field.columnName}", new Float(storageData.${field.fieldGetter}()));
+        <#else>
+            map.put((Object)"${field.columnName}", storageData.${field.fieldGetter}());
+        </#if>
+    </#list>
+    <#list persistentFields as field>
+        <#if field.typeName == "long">
+            map.put((Object)"${field.columnName}", new Long(storageData.${field.fieldGetter}()));
+        <#elseif field.typeName == "int">
+            map.put((Object)"${field.columnName}", new Integer(storageData.${field.fieldGetter}()));
+        <#elseif field.typeName == "double">
+            map.put((Object)"${field.columnName}", new Double(storageData.${field.fieldGetter}()));
+        <#elseif field.typeName == "float">
+            map.put((Object)"${field.columnName}", new Float(storageData.${field.fieldGetter}()));
+        <#else>
+            map.put((Object)"${field.columnName}", storageData.${field.fieldGetter}());
+        </#if>
+    </#list>
+    return map;
+}
\ No newline at end of file
diff --git a/oap-server/oal-rt/src/main/resources/code-templates/metrics-builder/map2Data.ftl b/oap-server/oal-rt/src/main/resources/code-templates/metrics-builder/map2Data.ftl
new file mode 100644
index 0000000..27f543a
--- /dev/null
+++ b/oap-server/oal-rt/src/main/resources/code-templates/metrics-builder/map2Data.ftl
@@ -0,0 +1,22 @@
+public org.apache.skywalking.oal.rt.metrics.${metricsName}Metrics map2Data(java.util.Map dbMap) {
+org.apache.skywalking.oal.rt.metrics.${metricsName}Metrics metrics = new org.apache.skywalking.oal.rt.metrics.${metricsName}Metrics();
+    <#list fieldsFromSource as field>
+        <#if field.typeName == "long" || field.typeName == "int" || field.typeName == "double" || field.typeName == "float">
+            metrics.${field.fieldSetter}(((Number)dbMap.get("${field.columnName}")).${field.typeName}Value());
+        <#elseif field.typeName == "java.lang.String">
+            metrics.${field.fieldSetter}((String)dbMap.get("${field.columnName}"));
+        <#else>
+            metrics.${field.fieldSetter}(new ${field.typeName}((String)dbMap.get("${field.columnName}")));
+        </#if>
+    </#list>
+    <#list persistentFields as field>
+        <#if field.typeName == "long" || field.typeName == "int" || field.typeName == "double" || field.typeName == "float">
+            metrics.${field.fieldSetter}(((Number)dbMap.get("${field.columnName}")).${field.typeName}Value());
+        <#elseif field.typeName == "java.lang.String">
+            metrics.${field.fieldSetter}((String)dbMap.get("${field.columnName}"));
+        <#else>
+            metrics.${field.fieldSetter}(new ${field.typeName}((String)dbMap.get("${field.columnName}")));
+        </#if>
+    </#list>
+return metrics;
+}
\ No newline at end of file