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 2020/04/22 15:14:55 UTC

[skywalking] branch metrics-system updated: Add metrics creation.

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

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


The following commit(s) were added to refs/heads/metrics-system by this push:
     new a37db8d  Add metrics creation.
a37db8d is described below

commit a37db8dacf5cf4ef05e18ee8c9b8fb8e27e85341
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Wed Apr 22 23:13:58 2020 +0800

    Add metrics creation.
---
 oap-server/pom.xml                                 |   1 +
 oap-server/server-bootstrap/pom.xml                |  11 +-
 .../src/main/resources/application.yml             |   5 +
 .../skywalking/oap/server/core/CoreModule.java     |   3 +
 .../oap/server/core/CoreModuleProvider.java        |   5 +-
 .../meter/{MeterFactory.java => MeterSystem.java}  | 133 +++++++++++++++------
 .../oap/server/core/analysis/meter/ScopeType.java} |  22 ++--
 .../server/core/analysis/meter/function/Avg.java   |  24 +++-
 .../skywalking/oap/server/core/CoreModuleTest.java |   2 +-
 oap-server/server-fetcher-plugin/pom.xml           |  36 ++++++
 .../prometheus-fetcher-plugin/pom.xml              |  39 ++++++
 .../module/PrometheusFetcherModule.java}           |  19 +--
 .../provider/PrometheusFetcherConfig.java}         |  15 +--
 .../provider/PrometheusFetcherProvider.java        |  86 +++++++++++++
 ...ywalking.oap.server.library.module.ModuleDefine |  19 +++
 ...alking.oap.server.library.module.ModuleProvider |  19 +++
 16 files changed, 369 insertions(+), 70 deletions(-)

diff --git a/oap-server/pom.xml b/oap-server/pom.xml
index b82034a..e04ad5a 100755
--- a/oap-server/pom.xml
+++ b/oap-server/pom.xml
@@ -45,6 +45,7 @@
         <module>server-configuration</module>
         <module>server-bootstrap</module>
         <module>server-tools</module>
+        <module>server-fetcher-plugin</module>
     </modules>
 
     <properties>
diff --git a/oap-server/server-bootstrap/pom.xml b/oap-server/server-bootstrap/pom.xml
index 5247fa2..7e46831 100644
--- a/oap-server/server-bootstrap/pom.xml
+++ b/oap-server/server-bootstrap/pom.xml
@@ -17,7 +17,8 @@
   ~
   -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <parent>
         <artifactId>oap-server</artifactId>
         <groupId>org.apache.skywalking</groupId>
@@ -123,6 +124,14 @@
         </dependency>
         <!-- receiver module -->
 
+        <!-- fetcher module -->
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>prometheus-fetcher-plugin</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <!-- fetcher module -->
+
         <!-- storage module -->
         <dependency>
             <groupId>org.apache.skywalking</groupId>
diff --git a/oap-server/server-bootstrap/src/main/resources/application.yml b/oap-server/server-bootstrap/src/main/resources/application.yml
index 4e715ac..d2bbae5 100755
--- a/oap-server/server-bootstrap/src/main/resources/application.yml
+++ b/oap-server/server-bootstrap/src/main/resources/application.yml
@@ -194,6 +194,11 @@ envoy-metric:
   default:
     alsHTTPAnalysis: ${SW_ENVOY_METRIC_ALS_HTTP_ANALYSIS:""}
 
+prometheus-fetcher:
+  selector: ${SW_PROMETHEUS_FETCHER:default}
+  default:
+    active: ${SW_PROMETHEUS_FETCHER_ACTIVE:false}
+
 receiver_zipkin:
   selector: ${SW_RECEIVER_ZIPKIN:-}
   default:
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
index 13c1cad..cb10177 100755
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
@@ -20,6 +20,7 @@ package org.apache.skywalking.oap.server.core;
 
 import java.util.ArrayList;
 import java.util.List;
+import org.apache.skywalking.oap.server.core.analysis.meter.MeterSystem;
 import org.apache.skywalking.oap.server.core.cache.NetworkAddressAliasCache;
 import org.apache.skywalking.oap.server.core.cache.ProfileTaskCache;
 import org.apache.skywalking.oap.server.core.command.CommandService;
@@ -71,6 +72,8 @@ public class CoreModule extends ModuleDefine {
         classes.add(IWorkerInstanceGetter.class);
         classes.add(IWorkerInstanceSetter.class);
 
+        classes.add(MeterSystem.class);
+
         addServerInterface(classes);
         addReceiverInterface(classes);
         addInsideService(classes);
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
index a93ce6d..531a8c5 100755
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
@@ -25,7 +25,7 @@ import org.apache.skywalking.oap.server.configuration.api.DynamicConfigurationSe
 import org.apache.skywalking.oap.server.core.analysis.ApdexThresholdConfig;
 import org.apache.skywalking.oap.server.core.analysis.DisableRegister;
 import org.apache.skywalking.oap.server.core.analysis.StreamAnnotationListener;
-import org.apache.skywalking.oap.server.core.analysis.meter.MeterFactory;
+import org.apache.skywalking.oap.server.core.analysis.meter.MeterSystem;
 import org.apache.skywalking.oap.server.core.analysis.metrics.ApdexMetrics;
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
 import org.apache.skywalking.oap.server.core.analysis.worker.TopNStreamProcessor;
@@ -156,7 +156,8 @@ public class CoreModuleProvider extends ModuleProvider {
         }
 
         try {
-            MeterFactory.init(getManager());
+            MeterSystem meterSystem = new MeterSystem(getManager());
+            this.registerServiceImplementation(MeterSystem.class, meterSystem);
         } catch (IOException e) {
             throw new ModuleStartException(e.getMessage(), e);
         }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/MeterFactory.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/MeterSystem.java
similarity index 50%
rename from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/MeterFactory.java
rename to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/MeterSystem.java
index 098adba..aba1f5b 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/MeterFactory.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/MeterSystem.java
@@ -21,6 +21,8 @@ package org.apache.skywalking.oap.server.core.analysis.meter;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.reflect.ClassPath;
 import java.io.IOException;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.util.HashMap;
 import java.util.Map;
 import javassist.CannotCompileException;
@@ -37,42 +39,47 @@ import org.apache.skywalking.oap.server.core.UnexpectedException;
 import org.apache.skywalking.oap.server.core.analysis.StreamDefinition;
 import org.apache.skywalking.oap.server.core.analysis.meter.function.AcceptableValue;
 import org.apache.skywalking.oap.server.core.analysis.meter.function.MeterFunction;
+import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
-import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.module.Service;
 
 /**
- * MeterFactory provides the API way to create {@link MetricsStreamProcessor} rather than manual analysis metrics or OAL
+ * MeterSystem provides the API way to create {@link MetricsStreamProcessor} rather than manual analysis metrics or OAL
  * script.
  *
  * @since 8.0.0
  */
 @Slf4j
-public class MeterFactory {
+public class MeterSystem implements Service {
     private static final String METER_CLASS_PACKAGE = "org.apache.skywalking.oap.server.core.analysis.meter.dynamic.";
-    private static ModuleManager MANAGER;
-    private static ClassPool CLASS_POOL;
-    private static Map<String, Class<? extends MeterFunction>> FUNCTION_REGISTER = new HashMap<>();
+    private ModuleManager MANAGER;
+    private ClassPool CLASS_POOL;
+    private Map<String, Class<? extends MeterFunction>> FUNCTION_REGISTER = new HashMap<>();
     /**
      * Host the dynamic meter prototype classes. These classes could be create dynamically through {@link
      * Object#clone()} in the runtime;
      */
     private static Map<String, MeterDefinition> METER_PROTOTYPES = new HashMap<>();
 
-    public static void init(final ModuleManager manager) throws IOException {
+    public MeterSystem(final ModuleManager manager) throws IOException {
         MANAGER = manager;
         CLASS_POOL = ClassPool.getDefault();
 
-        ClassPath classpath = ClassPath.from(MeterFactory.class.getClassLoader());
+        ClassPath classpath = ClassPath.from(MeterSystem.class.getClassLoader());
         ImmutableSet<ClassPath.ClassInfo> classes = classpath.getTopLevelClassesRecursive("org.apache.skywalking");
         for (ClassPath.ClassInfo classInfo : classes) {
-            Class<?> aClass = classInfo.load();
-
-            if (aClass.isAnnotationPresent(MeterFunction.class)) {
-                MeterFunction metricsFunction = aClass.getAnnotation(MeterFunction.class);
+            Class<?> functionClass = classInfo.load();
+
+            if (functionClass.isAnnotationPresent(MeterFunction.class)) {
+                MeterFunction metricsFunction = functionClass.getAnnotation(MeterFunction.class);
+                if (!AcceptableValue.class.isAssignableFrom(functionClass)) {
+                    throw new IllegalArgumentException(
+                        "Function " + functionClass.getCanonicalName() + " doesn't implement AcceptableValue.");
+                }
                 FUNCTION_REGISTER.put(
                     metricsFunction.functionName(),
-                    (Class<? extends MeterFunction>) aClass
+                    (Class<? extends MeterFunction>) functionClass
                 );
             }
         }
@@ -84,28 +91,57 @@ public class MeterFactory {
      *
      * @param metricsName  The name used as the storage eneity and in the query stage.
      * @param functionName The function provided through {@link MeterFunction}.
-     * @return {@link AcceptableValue} to accept the value for further distributed calculation.
+     * @return true if created, false if it exists.
+     * @throws IllegalArgumentException if the parameter can't match the expectation.
+     * @throws UnexpectedException      if binary code manipulation fails or stream core failure.
      */
-    public synchronized AcceptableValue create(String metricsName, String functionName, ScopeType type) {
+    public synchronized <T> boolean create(String metricsName,
+                                           String functionName,
+                                           ScopeType type,
+                                           Class<T> dataType) throws IllegalArgumentException {
         MeterDefinition meterDefinition = METER_PROTOTYPES.get(metricsName);
         if (meterDefinition != null) {
-            return meterDefinition.getMeterPrototype().createNew();
+            return false;
         } else {
             /**
              * Create a new meter class dynamically.
              */
             final Class<? extends MeterFunction> meterFunction = FUNCTION_REGISTER.get(functionName);
+
             if (meterFunction == null) {
-                throw new IllegalArgumentException("Function " + functionName + "can't be found.");
+                throw new IllegalArgumentException("Function " + functionName + " can't be found.");
+            }
+
+            boolean foundDataType = false;
+            String acceptance = null;
+            for (final Type genericInterface : meterFunction.getGenericInterfaces()) {
+                ParameterizedType parameterizedType = (ParameterizedType) genericInterface;
+                if (parameterizedType.getRawType().getTypeName().equals(AcceptableValue.class.getName())) {
+                    Type[] arguments = parameterizedType.getActualTypeArguments();
+                    if (arguments[0].equals(dataType)) {
+                        foundDataType = true;
+                    } else {
+                        acceptance = arguments[0].getTypeName();
+                    }
+                }
+            }
+            if (!foundDataType) {
+                throw new IllegalArgumentException("Function " + functionName
+                                                       + " requires <" + acceptance + "> in AcceptableValue"
+                                                       + " but using " + dataType.getName() + " in the creation");
             }
+
             final CtClass parentClass;
             try {
                 parentClass = CLASS_POOL.get(meterFunction.getCanonicalName());
+                if (!Metrics.class.isAssignableFrom(meterFunction)) {
+                    throw new IllegalArgumentException("Function " + functionName + " doesn't inherit from Metrics.");
+                }
             } catch (NotFoundException e) {
-                throw new IllegalArgumentException("Function " + functionName + "can't be found by javaassist.");
+                throw new IllegalArgumentException("Function " + functionName + " can't be found by javaassist.");
             }
             final String className = formatName(metricsName);
-            CtClass metricsClass = CLASS_POOL.makeClass(className, parentClass);
+            CtClass metricsClass = CLASS_POOL.makeClass(METER_CLASS_PACKAGE + className, parentClass);
 
             /**
              * Create empty construct
@@ -124,8 +160,8 @@ public class MeterFactory {
             try {
                 metricsClass.addMethod(CtNewMethod.make(
                     ""
-                        + "public AcceptableValue<T> createNew() {"
-                        + "    return new " + className + "();"
+                        + "public org.apache.skywalking.oap.server.core.analysis.meter.function.AcceptableValue createNew() {"
+                        + "    return new " + METER_CLASS_PACKAGE + className + "();"
                         + " }"
                     , metricsClass));
             } catch (CannotCompileException e) {
@@ -135,18 +171,19 @@ public class MeterFactory {
 
             Class targetClass;
             try {
-                targetClass = metricsClass.toClass(MeterFactory.class.getClassLoader(), null);
+                targetClass = metricsClass.toClass(MeterSystem.class.getClassLoader(), null);
                 AcceptableValue prototype = (AcceptableValue) targetClass.newInstance();
-                METER_PROTOTYPES.put(metricsName, new MeterDefinition(type, prototype));
+                METER_PROTOTYPES.put(metricsName, new MeterDefinition(type, prototype, dataType));
 
                 log.debug("Generate metrics class, " + metricsClass.getName());
 
                 MetricsStreamProcessor.getInstance().create(
                     MANAGER,
-                    new StreamDefinition(metricsName, type.scopeId, prototype.builder(), MetricsStreamProcessor.class),
+                    new StreamDefinition(
+                        metricsName, type.getScopeId(), prototype.builder(), MetricsStreamProcessor.class),
                     targetClass
                 );
-                return prototype;
+                return true;
             } catch (CannotCompileException | IllegalAccessException | InstantiationException e) {
                 log.error("Can't compile/load/init " + className + ".", e);
                 throw new UnexpectedException(e.getMessage(), e);
@@ -154,21 +191,42 @@ public class MeterFactory {
         }
     }
 
-    private String formatName(String metricsName) {
-        return METER_CLASS_PACKAGE + metricsName.toLowerCase();
-    }
+    /**
+     * Create an {@link AcceptableValue} instance for streaming calculation. AcceptableValue instance is stateful,
+     * shouldn't do {@link AcceptableValue#accept(String, Object)} once it is pushed into {@link
+     * #doStreamingCalculation(AcceptableValue)}.
+     *
+     * @param metricsName A defined metrics name. Use {@link #create(String, String, ScopeType, Class)} to define a new
+     *                    one.
+     * @param dataType    class type of the input of {@link AcceptableValue}
+     * @return usable an {@link AcceptableValue} instance.
+     */
+    public <T> AcceptableValue<T> buildMetrics(String metricsName,
+                                               Class<T> dataType) {
+        MeterDefinition meterDefinition = METER_PROTOTYPES.get(metricsName);
+        if (meterDefinition == null) {
+            throw new IllegalArgumentException("Uncreated metrics " + metricsName);
+        }
+        if (!meterDefinition.getScopeType().equals(dataType)) {
+            throw new IllegalArgumentException(
+                "Unmatched metrics data type, request for " + dataType.getName()
+                    + ", but defined as " + meterDefinition.getDataType());
+        }
 
-    public enum ScopeType {
-        SERVICE(DefaultScopeDefine.SERVICE),
-        SERVICE_INSTANCE(DefaultScopeDefine.SERVICE_INSTANCE),
-        ENDPOINT(DefaultScopeDefine.ENDPOINT);
+        return meterDefinition.getMeterPrototype().createNew();
+    }
 
-        @Getter
-        private final int scopeId;
+    /**
+     * Active the {@link MetricsStreamProcessor#in(Metrics)} for streaming calculation.
+     *
+     * @param acceptableValue should only be created through {@link #create(String, String, ScopeType, Class)}
+     */
+    public void doStreamingCalculation(AcceptableValue acceptableValue) {
+        MetricsStreamProcessor.getInstance().in((Metrics) acceptableValue);
+    }
 
-        ScopeType(final int scopeId) {
-            this.scopeId = scopeId;
-        }
+    private String formatName(String metricsName) {
+        return metricsName.toLowerCase();
     }
 
     @RequiredArgsConstructor
@@ -176,5 +234,6 @@ public class MeterFactory {
     private class MeterDefinition {
         private final ScopeType scopeType;
         private final AcceptableValue meterPrototype;
+        private final Class<?> dataType;
     }
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/ScopeType.java
similarity index 65%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/ScopeType.java
index 65d2fb6..9907e56 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/ScopeType.java
@@ -16,16 +16,20 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.oap.server.core.analysis.meter;
 
-import org.junit.Assert;
-import org.junit.Test;
+import lombok.Getter;
+import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
+public enum ScopeType {
+    SERVICE(DefaultScopeDefine.SERVICE),
+    SERVICE_INSTANCE(DefaultScopeDefine.SERVICE_INSTANCE),
+    ENDPOINT(DefaultScopeDefine.ENDPOINT);
 
-        Assert.assertEquals(28, coreModule.services().length);
+    @Getter
+    private final int scopeId;
+
+    ScopeType(final int scopeId) {
+        this.scopeId = scopeId;
     }
-}
+}
\ No newline at end of file
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/Avg.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/Avg.java
index 1328934..828d6bf 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/Avg.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/meter/function/Avg.java
@@ -18,10 +18,12 @@
 
 package org.apache.skywalking.oap.server.core.analysis.meter.function;
 
+import java.util.HashMap;
 import java.util.Map;
 import lombok.Getter;
 import lombok.Setter;
 import org.apache.skywalking.oap.server.core.Const;
+import org.apache.skywalking.oap.server.core.UnexpectedException;
 import org.apache.skywalking.oap.server.core.analysis.metrics.LongAvgMetrics;
 import org.apache.skywalking.oap.server.core.analysis.metrics.Metrics;
 import org.apache.skywalking.oap.server.core.remote.grpc.proto.RemoteData;
@@ -99,15 +101,31 @@ public abstract class Avg extends LongAvgMetrics implements AcceptableValue<Long
     }
 
     public static class AvgStorageBuilder implements StorageBuilder<Avg> {
-
         @Override
         public Avg map2Data(final Map<String, Object> dbMap) {
-            return null;
+            Avg metrics = new Avg() {
+                @Override
+                public AcceptableValue<Long> createNew() {
+                    throw new UnexpectedException("createNew should not be called");
+                }
+            };
+            metrics.setSummation(((Number) dbMap.get(SUMMATION)).longValue());
+            metrics.setValue(((Number) dbMap.get(VALUE)).longValue());
+            metrics.setCount(((Number) dbMap.get(COUNT)).longValue());
+            metrics.setTimeBucket(((Number) dbMap.get(TIME_BUCKET)).longValue());
+            metrics.setEntityId((String) dbMap.get(ENTITY_ID));
+            return metrics;
         }
 
         @Override
         public Map<String, Object> data2Map(final Avg storageData) {
-            return null;
+            Map<String, Object> map = new HashMap<>();
+            map.put(SUMMATION, storageData.getSummation());
+            map.put(VALUE, storageData.getValue());
+            map.put(COUNT, storageData.getCount());
+            map.put(TIME_BUCKET, storageData.getTimeBucket());
+            map.put(ENTITY_ID, storageData.getEntityId());
+            return map;
         }
     }
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
index 65d2fb6..3d09e3e 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
@@ -26,6 +26,6 @@ public class CoreModuleTest {
     public void testOpenServiceList() {
         CoreModule coreModule = new CoreModule();
 
-        Assert.assertEquals(28, coreModule.services().length);
+        Assert.assertEquals(29, coreModule.services().length);
     }
 }
diff --git a/oap-server/server-fetcher-plugin/pom.xml b/oap-server/server-fetcher-plugin/pom.xml
new file mode 100644
index 0000000..ea346f5
--- /dev/null
+++ b/oap-server/server-fetcher-plugin/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>oap-server</artifactId>
+        <groupId>org.apache.skywalking</groupId>
+        <version>8.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>server-fetcher-plugin</artifactId>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>prometheus-fetcher-plugin</module>
+    </modules>
+</project>
\ No newline at end of file
diff --git a/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/pom.xml b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/pom.xml
new file mode 100644
index 0000000..5a46450
--- /dev/null
+++ b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>server-fetcher-plugin</artifactId>
+        <groupId>org.apache.skywalking</groupId>
+        <version>8.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>prometheus-fetcher-plugin</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>server-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/prometheus/module/PrometheusFetcherModule.java
similarity index 67%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/prometheus/module/PrometheusFetcherModule.java
index 65d2fb6..356a784 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/prometheus/module/PrometheusFetcherModule.java
@@ -16,16 +16,19 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.oap.server.fetcher.prometheus.module;
 
-import org.junit.Assert;
-import org.junit.Test;
+import org.apache.skywalking.oap.server.library.module.ModuleDefine;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
+public class PrometheusFetcherModule extends ModuleDefine {
+    public static final String NAME = "prometheus-fetcher";
 
-        Assert.assertEquals(28, coreModule.services().length);
+    public PrometheusFetcherModule() {
+        super(NAME);
+    }
+
+    @Override
+    public Class[] services() {
+        return new Class[0];
     }
 }
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/prometheus/provider/PrometheusFetcherConfig.java
similarity index 73%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/prometheus/provider/PrometheusFetcherConfig.java
index 65d2fb6..0c004af 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/prometheus/provider/PrometheusFetcherConfig.java
@@ -16,16 +16,13 @@
  *
  */
 
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.oap.server.fetcher.prometheus.provider;
 
-import org.junit.Assert;
-import org.junit.Test;
+import lombok.Getter;
+import org.apache.skywalking.oap.server.library.module.ModuleConfig;
 
-public class CoreModuleTest {
-    @Test
-    public void testOpenServiceList() {
-        CoreModule coreModule = new CoreModule();
+@Getter
+public class PrometheusFetcherConfig extends ModuleConfig {
+    private boolean active;
 
-        Assert.assertEquals(28, coreModule.services().length);
-    }
 }
diff --git a/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/prometheus/provider/PrometheusFetcherProvider.java b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/prometheus/provider/PrometheusFetcherProvider.java
new file mode 100644
index 0000000..afd6b52
--- /dev/null
+++ b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/java/org/apache/skywalking/oap/server/fetcher/prometheus/provider/PrometheusFetcherProvider.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ *
+ */
+
+package org.apache.skywalking.oap.server.fetcher.prometheus.provider;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.analysis.meter.MeterSystem;
+import org.apache.skywalking.oap.server.core.analysis.meter.ScopeType;
+import org.apache.skywalking.oap.server.core.analysis.meter.function.AcceptableValue;
+import org.apache.skywalking.oap.server.fetcher.prometheus.module.PrometheusFetcherModule;
+import org.apache.skywalking.oap.server.library.module.ModuleConfig;
+import org.apache.skywalking.oap.server.library.module.ModuleDefine;
+import org.apache.skywalking.oap.server.library.module.ModuleProvider;
+import org.apache.skywalking.oap.server.library.module.ModuleStartException;
+import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
+
+public class PrometheusFetcherProvider extends ModuleProvider {
+    private final PrometheusFetcherConfig config;
+
+    public PrometheusFetcherProvider() {
+        config = new PrometheusFetcherConfig();
+    }
+
+    @Override
+    public String name() {
+        return "default";
+    }
+
+    @Override
+    public Class<? extends ModuleDefine> module() {
+        return PrometheusFetcherModule.class;
+    }
+
+    @Override
+    public ModuleConfig createConfigBeanIfAbsent() {
+        return config;
+    }
+
+    @Override
+    public void prepare() throws ServiceNotProvidedException, ModuleStartException {
+
+    }
+
+    @Override
+    public void start() throws ServiceNotProvidedException, ModuleStartException {
+        final MeterSystem service = getManager().find(CoreModule.NAME).provider().getService(MeterSystem.class);
+        service.create(
+            "test_long_metrics", "avg", ScopeType.SERVICE, Long.class);
+    }
+
+    @Override
+    public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException {
+        final MeterSystem service = getManager().find(CoreModule.NAME).provider().getService(MeterSystem.class);
+        final AcceptableValue<Long> testLongMetrics = service.buildMetrics("test_long_metrics", Long.class);
+        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() {
+            @Override
+            public void run() {
+                final AcceptableValue<Long> value = testLongMetrics.createNew();
+                value.accept("abc", 5L);
+                service.doStreamingCalculation(value);
+            }
+        }, 2, 2, TimeUnit.SECONDS);
+    }
+
+    @Override
+    public String[] requiredModules() {
+        return new String[] {CoreModule.NAME};
+    }
+}
diff --git a/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine
new file mode 100644
index 0000000..9d67848
--- /dev/null
+++ b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+#
+
+org.apache.skywalking.oap.server.fetcher.prometheus.module.PrometheusFetcherModule
\ No newline at end of file
diff --git a/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
new file mode 100644
index 0000000..a14eab4
--- /dev/null
+++ b/oap-server/server-fetcher-plugin/prometheus-fetcher-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+#
+
+org.apache.skywalking.oap.server.fetcher.prometheus.provider.PrometheusFetcherProvider
\ No newline at end of file