diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index ff4ac00117..94f0fd2975 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -78,6 +78,8 @@ jobs:
class: org.apache.skywalking.e2e.meter.MeterE2E
- name: Alarm
class: org.apache.skywalking.e2e.alarm.AlarmE2E
+ - name: Zabbix
+ class: org.apache.skywalking.e2e.zabbix.ZabbixE2E
steps:
- uses: actions/checkout@v2
with:
diff --git a/CHANGES.md b/CHANGES.md
index cfb552f345..38e4a52320 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -18,6 +18,7 @@ Release Notes.
* Add a new concept "Event" and its implementations to collect events.
* Add some defensive codes for NPE and bump up Kubernetes client version to expose exception stack trace.
* Update the `timestamp` field type for `LogQuery`.
+* Support Zabbix protocol to receive agent metrics.
#### UI
* Update selector scroller to show in all pages.
diff --git a/README.md b/README.md
index 2ee5a5deb0..4cfe97c82c 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ including
1. LUA agent especially for Nginx, OpenResty.
1. Browser agent.
1. Service Mesh Observability. Control panel and data panel.
-1. Metrics system, including Prometheus, OpenTelemetry, Spring Sleuth(Micrometer).
+1. Metrics system, including Prometheus, OpenTelemetry, Spring Sleuth(Micrometer), Zabbix.
1. Logs.
1. Zipkin v1/v2 and Jaeger gRPC format with limited topology and metrics analysis.(Experimental).
diff --git a/apm-dist-es7/src/main/assembly/binary-es7.xml b/apm-dist-es7/src/main/assembly/binary-es7.xml
index e47b334957..d5b84cf9ae 100644
--- a/apm-dist-es7/src/main/assembly/binary-es7.xml
+++ b/apm-dist-es7/src/main/assembly/binary-es7.xml
@@ -56,6 +56,7 @@
fetcher-prom-rules/*.yamlenvoy-metrics-rules/*.yamlmeter-analyzer-config/*.yaml
+ zabbix-rules/*.yamlotel-oc-rules/*ui-initialized-templates/*
diff --git a/apm-dist/src/main/assembly/binary.xml b/apm-dist/src/main/assembly/binary.xml
index 02586211bb..56c0f7af4d 100644
--- a/apm-dist/src/main/assembly/binary.xml
+++ b/apm-dist/src/main/assembly/binary.xml
@@ -56,6 +56,7 @@
fetcher-prom-rules/*.yamlenvoy-metrics-rules/*.yamlmeter-analyzer-config/*.yaml
+ zabbix-rules/*.yamlotel-oc-rules/*ui-initialized-templates/*
diff --git a/docs/en/setup/backend/backend-receivers.md b/docs/en/setup/backend/backend-receivers.md
index 36c56e7e24..6e68632d70 100644
--- a/docs/en/setup/backend/backend-receivers.md
+++ b/docs/en/setup/backend/backend-receivers.md
@@ -17,6 +17,7 @@ We have following receivers, and `default` implementors are provided in our Apac
1. **receiver-log**. gRPC services accept log data.
1. **configuration-discovery**. gRPC services handle configurationDiscovery.
1. **receiver-event**. gRPC services to handle events data.
+1. **receiver-zabbix**. See [details](backend-zabbix.md).
1. Experimental receivers. All following receivers are in the POC stage, not production ready.
1. **receiver_zipkin**. See [details](#zipkin-receiver). (Experimental)
1. **receiver_jaeger**. See [details](#jaeger-receiver). (Experimental)
diff --git a/docs/en/setup/backend/backend-zabbix.md b/docs/en/setup/backend/backend-zabbix.md
new file mode 100644
index 0000000000..513062b2e7
--- /dev/null
+++ b/docs/en/setup/backend/backend-zabbix.md
@@ -0,0 +1,73 @@
+# Zabbix Receiver
+Zabbix receiver is accepting the metrics of [Zabbix Agent Active Checks protocol](https://www.zabbix.com/documentation/current/manual/appendix/items/activepassive#active_checks) format into the [Meter System](./../../concepts-and-designs/meter.md).
+Zabbix Agent is base on GPL-2.0 License.
+
+## Module define
+```yaml
+receiver-zabbix:
+ selector: ${SW_RECEIVER_ZABBIX:default}
+ default:
+ # Export tcp port, Zabbix agent could connected and transport data
+ port: 10051
+ # Bind to host
+ host: 0.0.0.0
+ # Enable config when receive agent request
+ activeFiles: agent
+```
+
+## Configuration file
+Zabbix receiver is configured via a configuration file. The configuration file defines everything related to receiving
+ from agents, as well as which rule files to load.
+
+OAP can load the configuration at bootstrap. If the new configuration is not well-formed, OAP fails to start up. The files
+are located at `$CLASSPATH/zabbix-rules`.
+
+The file is written in YAML format, defined by the scheme described below. Square brackets indicate that a parameter is optional.
+
+An example for zabbix agent configuration could be found [here](../../../../test/e2e/e2e-test/docker/zabbix/zabbix_agentd.conf).
+You could find the Zabbix agent detail items from [Zabbix Agent documentation](https://www.zabbix.com/documentation/current/manual/config/items/itemtypes/zabbix_agent).
+
+### Configuration file
+
+```yaml
+# insert metricPrefix into metric name: _
+metricPrefix:
+# expSuffix is appended to all expression in this file.
+expSuffix:
+# Datasource from Zabbix Item keys.
+requiredZabbixItemKeys:
+ -
+# Support agent entities information.
+entities:
+ # Allow hostname patterns to build metrics.
+ hostPatterns:
+ -
+ # Customized metrics label before parse to meter system.
+ labels:
+ [- ]
+# Metrics rule allow you to recompute queries.
+metrics:
+ [ - ]
+```
+
+####
+
+```yaml
+# Define the label name. The label value must query from `value` or `fromItem` attribute.
+name:
+# Appoint value to label.
+[value: ]
+# Query label value from Zabbix Agent Item key.
+[fromItem: ]
+```
+
+####
+
+```yaml
+# The name of rule, which combinates with a prefix 'meter_' as the index/table name in storage.
+name:
+# MAL expression.
+exp:
+```
+
+More about MAL, please refer to [mal.md](../../concepts-and-designs/mal.md).
diff --git a/docs/en/setup/backend/configuration-vocabulary.md b/docs/en/setup/backend/configuration-vocabulary.md
index 2d4dca2b60..a26447db6f 100644
--- a/docs/en/setup/backend/configuration-vocabulary.md
+++ b/docs/en/setup/backend/configuration-vocabulary.md
@@ -173,6 +173,10 @@ core|default|role|Option values, `Mixed/Receiver/Aggregator`. **Receiver** mode
| receiver-jvm| default| Read [receiver doc](backend-receivers.md) for more details | - | - |
| receiver-clr| default| Read [receiver doc](backend-receivers.md) for more details | - | - |
| receiver-profile| default| Read [receiver doc](backend-receivers.md) for more details | - | - |
+| receiver-zabbix| default| Read [receiver doc](backend-zabbix.md) for more details | - | - |
+| - | - | port| Exported tcp port, Zabbix agent could connect and transport data| SW_RECEIVER_ZABBIX_PORT | 10051 |
+| - | - | host| Bind to host| SW_RECEIVER_ZABBIX_HOST | 0.0.0.0 |
+| - | - | activeFiles| Enable config when receive agent request| SW_RECEIVER_ZABBIX_ACTIVE_FILES | agent |
| service-mesh| default| Read [receiver doc](backend-receivers.md) for more details | - | - |
| envoy-metric| default| Read [receiver doc](backend-receivers.md) for more details | - | - |
| - | - | acceptMetricsService | Open Envoy Metrics Service analysis | SW_ENVOY_METRIC_SERVICE | true|
diff --git a/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/SampleFamily.java b/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/SampleFamily.java
index 9580d85fb5..bb2329cf0f 100644
--- a/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/SampleFamily.java
+++ b/oap-server/analyzer/meter-analyzer/src/main/java/org/apache/skywalking/oap/meter/analyzer/dsl/SampleFamily.java
@@ -28,7 +28,6 @@ import groovy.lang.Closure;
import io.vavr.Function2;
import io.vavr.Tuple;
import io.vavr.Tuple2;
-import java.util.function.DoubleBinaryOperator;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.EqualsAndHashCode;
@@ -48,6 +47,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.DoubleBinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
diff --git a/oap-server/server-bootstrap/pom.xml b/oap-server/server-bootstrap/pom.xml
index 46d906299d..306cf3d5a8 100644
--- a/oap-server/server-bootstrap/pom.xml
+++ b/oap-server/server-bootstrap/pom.xml
@@ -141,6 +141,11 @@
skywalking-event-receiver-plugin${project.version}
+
+ org.apache.skywalking
+ skywalking-zabbix-receiver-plugin
+ ${project.version}
+
@@ -277,6 +282,7 @@
meter-analyzer-config/otel-oc-rules/ui-initialized-templates/
+ zabbix-rules/
diff --git a/oap-server/server-bootstrap/src/main/resources/application.yml b/oap-server/server-bootstrap/src/main/resources/application.yml
index 5b9c1c4cf8..c765d3f42a 100755
--- a/oap-server/server-bootstrap/src/main/resources/application.yml
+++ b/oap-server/server-bootstrap/src/main/resources/application.yml
@@ -266,6 +266,13 @@ receiver-profile:
selector: ${SW_RECEIVER_PROFILE:default}
default:
+receiver-zabbix:
+ selector: ${SW_RECEIVER_ZABBIX:default}
+ default:
+ port: ${SW_RECEIVER_ZABBIX_PORT:10051}
+ host: ${SW_RECEIVER_ZABBIX_HOST:0.0.0.0}
+ activeFiles: ${SW_RECEIVER_ZABBIX_ACTIVE_FILES:agent}
+
service-mesh:
selector: ${SW_SERVICE_MESH:default}
default:
diff --git a/oap-server/server-bootstrap/src/main/resources/ui-initialized-templates/vm.yml b/oap-server/server-bootstrap/src/main/resources/ui-initialized-templates/vm.yml
index 051bcb1afe..0f6584b1bd 100644
--- a/oap-server/server-bootstrap/src/main/resources/ui-initialized-templates/vm.yml
+++ b/oap-server/server-bootstrap/src/main/resources/ui-initialized-templates/vm.yml
@@ -154,7 +154,7 @@ templates:
"chartType": "ChartLine",
"aggregation": "/",
"aggregationNum": "1024",
- "unit": "KB/s"
+ "unit": "KB/s - OTEL, ops - Zabbix"
},
{
"width": "4",
diff --git a/oap-server/server-bootstrap/src/main/resources/zabbix-rules/agent.yaml b/oap-server/server-bootstrap/src/main/resources/zabbix-rules/agent.yaml
new file mode 100644
index 0000000000..b0a5325ca7
--- /dev/null
+++ b/oap-server/server-bootstrap/src/main/resources/zabbix-rules/agent.yaml
@@ -0,0 +1,89 @@
+# 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.
+
+metricPrefix: meter_vm
+expSuffix: tag({tags -> tags.host = 'vm::' + tags.host}).service(['host'])
+entities:
+ hostPatterns:
+ - .+
+ labels:
+requiredZabbixItemKeys:
+ # cpu
+ - system.cpu.load[all,avg15]
+ - system.cpu.load[all,avg1]
+ - system.cpu.load[all,avg5]
+ - system.cpu.util[,guest]
+ - system.cpu.util[,guest_nice]
+ - system.cpu.util[,idle]
+ - system.cpu.util[,interrupt]
+ - system.cpu.util[,iowait]
+ - system.cpu.util[,nice]
+ - system.cpu.util[,softirq]
+ - system.cpu.util[,steal]
+ - system.cpu.util[,system]
+ - system.cpu.util[,user]
+ # memory
+ - vm.memory.size[available]
+ - vm.memory.size[pavailable]
+ - vm.memory.size[total]
+ - vm.memory.size[pavailable]
+ # swap
+ - system.swap.size[,free]
+ - system.swap.size[,total]
+ - system.swap.size[,pused]
+ # file
+ - vfs.fs.inode[/,pused]
+ - vfs.fs.size[/,total]
+ - vfs.fs.size[/,used]
+ - vfs.dev.read[,ops,avg1]
+ - vfs.dev.write[,ops,avg1]
+
+metrics:
+ # cpu
+ - name: cpu_load1
+ exp: system_cpu_load.tagEqual('2', 'avg1').avg(['host']) * 100
+ - name: cpu_load5
+ exp: system_cpu_load.tagEqual('2', 'avg5').avg(['host']) * 100
+ - name: cpu_load15
+ exp: system_cpu_load.tagEqual('2', 'avg15').avg(['host']) * 100
+ - name: cpu_average_used
+ exp: system_cpu_util.avg(['2', 'host'])
+ - name: cpu_total_percentage
+ exp: system_cpu_util.tagNotEqual('2', 'idle').sum(['host'])
+ # memory
+ - name: memory_total
+ exp: vm_memory_size.tagEqual('1', 'total').avg(['host'])
+ - name: memory_available
+ exp: vm_memory_size.tagEqual('1', 'available').avg(['host'])
+ - name: memory_used
+ exp: vm_memory_size.tagEqual('1', 'total').avg(['host']) - vm_memory_size.tagEqual('1', 'available').avg(['host'])
+ # swap
+ - name: memory_swap_free
+ exp: system_swap_size.tagEqual('2', 'free').avg(['host'])
+ - name: memory_swap_total
+ exp: system_swap_size.tagEqual('2', 'total').avg(['host'])
+ - name: memory_swap_percentage
+ exp: system_swap_size.tagEqual('2', 'pused')
+ # file
+ - name: filesystem_percentage
+ exp: vfs_fs_inode.tagEqual('2', 'pused').avg(['1', 'host'])
+ - name: vfs_fs_size
+ exp: vfs_fs_size.avg(['1', '2', 'host'])
+ - name: disk_read
+ # `* 1024` is for adapting to `divide 1024` by the VM UI template configuration, which converts `byte`->`kb` because of OTEL/Prometheus Node exporter.
+ exp: vfs_dev_read * 1024
+ - name: disk_written
+ # `* 1024` is for adapting to `divide 1024` by the VM UI template configuration, which converts `byte`->`kb` because of OTEL/Prometheus Node exporter.
+ exp: vfs_dev_write * 1024
diff --git a/oap-server/server-receiver-plugin/pom.xml b/oap-server/server-receiver-plugin/pom.xml
index a08c77a0c0..c9ceeb52a8 100644
--- a/oap-server/server-receiver-plugin/pom.xml
+++ b/oap-server/server-receiver-plugin/pom.xml
@@ -45,6 +45,7 @@
skywalking-log-recevier-pluginconfiguration-discovery-receiver-pluginskywalking-event-receiver-plugin
+ skywalking-zabbix-receiver-plugin
diff --git a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/pom.xml b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/pom.xml
new file mode 100644
index 0000000000..daef5d2963
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/pom.xml
@@ -0,0 +1,50 @@
+
+
+
+
+ server-receiver-plugin
+ org.apache.skywalking
+ 8.5.0-SNAPSHOT
+
+ 4.0.0
+
+ skywalking-zabbix-receiver-plugin
+ jar
+
+
+
+ org.apache.skywalking
+ skywalking-sharing-server-plugin
+ ${project.version}
+
+
+ org.apache.skywalking
+ meter-analyzer
+ ${project.version}
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ test
+
+
+
+
\ No newline at end of file
diff --git a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/module/ZabbixReceiverModule.java b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/module/ZabbixReceiverModule.java
new file mode 100644
index 0000000000..18dfe73fc8
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/module/ZabbixReceiverModule.java
@@ -0,0 +1,34 @@
+/*
+ * 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.receiver.zabbix.module;
+
+import org.apache.skywalking.oap.server.library.module.ModuleDefine;
+
+public class ZabbixReceiverModule extends ModuleDefine {
+ public static final String NAME = "receiver-zabbix";
+
+ public ZabbixReceiverModule() {
+ super(NAME);
+ }
+
+ @Override
+ public Class[] services() {
+ return new Class[0];
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixMetrics.java b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixMetrics.java
new file mode 100644
index 0000000000..078dfd82d7
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixMetrics.java
@@ -0,0 +1,312 @@
+/*
+ * 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.receiver.zabbix.provider;
+
+import com.google.common.collect.ImmutableMap;
+import io.vavr.Tuple;
+import io.vavr.Tuple2;
+import lombok.Builder;
+import lombok.Data;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.commons.lang3.time.StopWatch;
+import org.apache.commons.text.StringTokenizer;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.oap.meter.analyzer.MetricConvert;
+import org.apache.skywalking.oap.meter.analyzer.dsl.Sample;
+import org.apache.skywalking.oap.meter.analyzer.dsl.SampleFamily;
+import org.apache.skywalking.oap.meter.analyzer.dsl.SampleFamilyBuilder;
+import org.apache.skywalking.oap.server.core.analysis.meter.MeterSystem;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+import org.apache.skywalking.oap.server.receiver.zabbix.provider.config.ZabbixConfig;
+import org.apache.skywalking.oap.server.receiver.zabbix.provider.protocol.bean.ZabbixRequest;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static com.google.common.collect.ImmutableMap.toImmutableMap;
+
+/**
+ * Management all Zabbix metrics
+ */
+@Slf4j
+public class ZabbixMetrics {
+
+ private final List originalConfigs;
+
+ /**
+ * All enabled service and instance group
+ */
+ private List allServices = new ArrayList<>();
+
+ public ZabbixMetrics(List originalConfigs, MeterSystem meterSystem) {
+ this.originalConfigs = originalConfigs;
+ initConfigs(meterSystem);
+ }
+
+ /**
+ * Get all key names when Zabbix agent queried
+ */
+ public Set getAllMonitorMetricNames(String hostName) {
+ // Find instance group
+ return findInstanceGroup(hostName).map(InstanceGroup::getEnabledKeys).orElse(null);
+ }
+
+ /**
+ * Receive agent data and convert to meter system
+ */
+ public ConvertStatics convertMetrics(List agentDataList) {
+ if (CollectionUtils.isEmpty(agentDataList)) {
+ return ConvertStatics.EMPTY;
+ }
+
+ return agentDataList.stream()
+ // Group by host
+ .collect(Collectors.groupingBy(ZabbixRequest.AgentData::getHost)).entrySet().stream()
+ // Convert every agent data list
+ .map(e -> findInstanceGroup(e.getKey()).map(instanceGroup -> instanceGroup.convertToMeter(e.getValue())).orElse(null))
+ .filter(Objects::nonNull)
+ // Merge all statics
+ .reduce(ConvertStatics::merge)
+ .orElse(ConvertStatics.EMPTY);
+ }
+
+ private Optional findInstanceGroup(String hostName) {
+ // Find service group, support using cache
+ return allServices.stream().filter(group -> group.matchesWithHostName(hostName)).findAny();
+ }
+
+ private void initConfigs(MeterSystem meterSystem) {
+ // Temporary instance group cache, encase generate multiple instance group
+ HashMap tmpGroupCache = new HashMap<>();
+
+ // Each config entities
+ originalConfigs.forEach(c ->
+ c.getEntities().getHostPatterns().forEach(instance ->
+ tmpGroupCache.computeIfAbsent(instance, ins -> {
+ InstanceGroup instanceGroup = new InstanceGroup(ins, meterSystem);
+ allServices.add(instanceGroup);
+ return instanceGroup;
+ }).appendMetrics(c)));
+ }
+
+ /**
+ * Metrics convert to meter system statics
+ */
+ @Builder
+ @Getter
+ public static class ConvertStatics {
+ public static final ConvertStatics EMPTY = ConvertStatics.builder().build();
+ private int total;
+ private int success;
+ private int failed;
+ private double useTime;
+
+ public ConvertStatics merge(ConvertStatics statics) {
+ this.total += statics.total;
+ this.success += statics.success;
+ this.failed += statics.failed;
+ this.useTime += statics.useTime;
+ return this;
+ }
+ }
+
+ /**
+ * The group of instances according to hostPatterns defined in Zabbix rule file
+ */
+ private static class InstanceGroup {
+ static final InstanceGroup EMPTY = new InstanceGroup("", null);
+
+ private final Pattern instancePattern;
+ private final MeterSystem meterSystem;
+ @Getter
+ private Set enabledKeys;
+ private List metricConverts;
+ private List labels;
+
+ public InstanceGroup(String instancePattern, MeterSystem meterSystem) {
+ this.instancePattern = Pattern.compile(instancePattern);
+ this.meterSystem = meterSystem;
+ this.enabledKeys = new HashSet<>();
+ this.metricConverts = new ArrayList<>();
+ this.labels = new ArrayList<>();
+ }
+
+ public void appendMetrics(ZabbixConfig config) {
+ // Append metrics to converters
+ metricConverts.add(new MetricConvert(config, meterSystem));
+
+ // Append labels and add to item keys
+ if (CollectionUtils.isNotEmpty(config.getEntities().getLabels())) {
+ labels.addAll(config.getEntities().getLabels());
+
+ config.getEntities().getLabels().stream().filter(l -> StringUtils.isNotBlank(l.getFromItem()))
+ .forEach(l -> enabledKeys.add(l.getFromItem()));
+ }
+
+ // Append all metric keys
+ enabledKeys.addAll(config.getRequiredZabbixItemKeys());
+ }
+
+ public boolean matchesWithHostName(String hostName) {
+ Matcher matcher = instancePattern.matcher(hostName);
+ return matcher.matches();
+ }
+
+ public ConvertStatics convertToMeter(List dataList) {
+ if (log.isDebugEnabled()) {
+ log.debug("Receive zabbix agent data: {}", dataList);
+ }
+ StopWatch stopWatch = new StopWatch();
+ Collection sampleFamilies = null;
+ try {
+ stopWatch.start();
+
+ // Parse config labels
+ Map configLabels = parseConfigLabels(dataList);
+
+ // Build metrics
+ ImmutableMap families = dataList.stream()
+ // Correct state
+ .filter(d -> d.getState() == 0 && NumberUtils.isParsable(d.getValue()))
+ // Parse data to list
+ .map(this::parseAgentData)
+ .map(b -> b.build(configLabels))
+ // Combine to sample family
+ .collect(Collectors.groupingBy(Sample::getName))
+ .entrySet().stream().collect(toImmutableMap(
+ Map.Entry::getKey,
+ e -> SampleFamilyBuilder.newBuilder(e.getValue().stream().toArray(Sample[]::new)).build()));
+
+ sampleFamilies = families.values();
+
+ // Each all converters
+ metricConverts.forEach(converter -> converter.toMeter(families));
+ } finally {
+ stopWatch.stop();
+ }
+
+ return ConvertStatics.builder()
+ .total(sampleFamilies.size())
+ // Setting all as success
+ .success(sampleFamilies.size())
+ .useTime(((double) stopWatch.getTime()) / 1000)
+ .build();
+ }
+
+ /**
+ * Parsing config labels from original value or agent data
+ */
+ private Map parseConfigLabels(List dataList) {
+ if (CollectionUtils.isEmpty(labels)) {
+ return Collections.emptyMap();
+ }
+
+ return labels.stream().map(label -> {
+ // Exists Value
+ if (StringUtil.isNotBlank(label.getValue())) {
+ return Tuple.of(label.getName(), label.getValue());
+ } else if (StringUtil.isNotBlank(label.getFromItem())) {
+ // Searching from Agent data
+ return dataList.stream()
+ .filter(d -> Objects.equals(d.getKey(), label.getFromItem())).findFirst()
+ .map(d -> Tuple.of(label.getName(), d.getValue())).orElse(null);
+ }
+ return null;
+ }).filter(Objects::nonNull).collect(Collectors.toMap(Tuple2::_1, Tuple2::_2));
+ }
+
+ /**
+ * Parsing Zabbix agent data to sample builder
+ */
+ private SampleBuilder parseAgentData(ZabbixRequest.AgentData data) {
+ String keyName = data.getKey();
+ SampleBuilder.SampleBuilderBuilder builder = SampleBuilder.builder();
+
+ if (keyName.contains("[") && keyName.endsWith("]")) {
+ String key = StringUtils.substringBefore(keyName, "[");
+
+ // Split params, support quote mode, label name start at 1
+ StringTokenizer tokenizer = new StringTokenizer(
+ StringUtils.substringAfter(keyName.substring(0, keyName.length() - 1), "["), ',', '\"');
+ tokenizer.setIgnoreEmptyTokens(false);
+ int inx = 1;
+ ImmutableMap.Builder paramBuilder = ImmutableMap.builder();
+ while (tokenizer.hasNext()) {
+ paramBuilder.put(String.valueOf(inx++), tokenizer.next());
+ }
+
+ builder.name(key).labels(paramBuilder.build());
+ } else {
+ builder.name(keyName).labels(ImmutableMap.of());
+ }
+
+ return builder.hostName(data.getHost())
+ .timestamp(TimeUnit.SECONDS.toMillis(data.getClock()))
+ .value(Double.parseDouble(data.getValue()))
+ .build();
+ }
+ }
+
+ @Builder
+ @Data
+ private static class SampleBuilder {
+
+ private final String name;
+ private final String hostName;
+ private final long timestamp;
+ private final ImmutableMap labels;
+ private final double value;
+
+ public Sample build(Map configLabels) {
+ return Sample.builder()
+ .name(escapedName(name))
+ .labels(ImmutableMap.builder()
+ // Put original labels
+ .putAll(labels)
+ // Put config labels
+ .putAll(configLabels)
+ // Put report instance to labels
+ .put("host", hostName)
+ .build())
+ .value(value)
+ .timestamp(timestamp).build();
+ }
+
+ // Returns the escaped name of the given one, with "." replaced by "_"
+ private String escapedName(final String name) {
+ return name.replaceAll("\\.", "_");
+ }
+ }
+
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixModuleConfig.java b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixModuleConfig.java
new file mode 100644
index 0000000000..b169892d02
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixModuleConfig.java
@@ -0,0 +1,47 @@
+/*
+ * 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.receiver.zabbix.provider;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.Const;
+import org.apache.skywalking.oap.server.library.module.ModuleConfig;
+
+@Setter
+@Getter
+public class ZabbixModuleConfig extends ModuleConfig {
+
+ /**
+ * Export tcp port
+ */
+ private int port = 10051;
+
+ /**
+ * Bind to host
+ */
+ private String host = "0.0.0.0";
+
+ public static final String CONFIG_PATH = "zabbix-rules";
+
+ /**
+ * active receive configs, files split by ","
+ */
+ private String activeFiles = Const.EMPTY_STRING;
+
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixReceiverProvider.java b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixReceiverProvider.java
new file mode 100644
index 0000000000..370d3da92c
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/ZabbixReceiverProvider.java
@@ -0,0 +1,95 @@
+/*
+ * 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.receiver.zabbix.provider;
+
+import com.google.common.base.Splitter;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.analysis.meter.MeterSystem;
+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;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+import org.apache.skywalking.oap.server.receiver.zabbix.module.ZabbixReceiverModule;
+import org.apache.skywalking.oap.server.receiver.zabbix.provider.config.ZabbixConfig;
+import org.apache.skywalking.oap.server.receiver.zabbix.provider.config.ZabbixConfigs;
+import org.apache.skywalking.oap.server.receiver.zabbix.provider.protocol.ZabbixServer;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ZabbixReceiverProvider extends ModuleProvider {
+ private ZabbixModuleConfig moduleConfig;
+ private List configs;
+ private ZabbixMetrics zabbixMetrics;
+
+ public ZabbixReceiverProvider() {
+ this.moduleConfig = new ZabbixModuleConfig();
+ }
+
+ @Override
+ public String name() {
+ return "default";
+ }
+
+ @Override
+ public Class extends ModuleDefine> module() {
+ return ZabbixReceiverModule.class;
+ }
+
+ @Override
+ public ModuleConfig createConfigBeanIfAbsent() {
+ return moduleConfig;
+ }
+
+ @Override
+ public void prepare() throws ServiceNotProvidedException, ModuleStartException {
+ configs = ZabbixConfigs.loadConfigs(ZabbixModuleConfig.CONFIG_PATH,
+ StringUtil.isEmpty(moduleConfig.getActiveFiles()) ? Collections.emptyList() : Splitter.on(",").splitToList(moduleConfig.getActiveFiles()));
+ }
+
+ @Override
+ public void start() throws ServiceNotProvidedException, ModuleStartException {
+ if (CollectionUtils.isNotEmpty(configs)) {
+ // Init metrics
+ zabbixMetrics = new ZabbixMetrics(configs, getManager().find(CoreModule.NAME).provider().getService(MeterSystem.class));
+
+ // Bind receiver server
+ ZabbixServer zabbixServer = new ZabbixServer(moduleConfig, zabbixMetrics);
+ try {
+ zabbixServer.start();
+ } catch (Exception e) {
+ throw new ModuleStartException(e.getMessage(), e);
+ }
+ }
+ }
+
+ @Override
+ public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException {
+ }
+
+ @Override
+ public String[] requiredModules() {
+ return new String[] {
+ CoreModule.NAME
+ };
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/config/ZabbixConfig.java b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/config/ZabbixConfig.java
new file mode 100644
index 0000000000..eebcf46fe9
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/config/ZabbixConfig.java
@@ -0,0 +1,58 @@
+/*
+ * 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.receiver.zabbix.provider.config;
+
+import lombok.Data;
+import org.apache.skywalking.oap.meter.analyzer.MetricRuleConfig;
+
+import java.util.List;
+
+@Data
+public class ZabbixConfig implements MetricRuleConfig {
+
+ private String metricPrefix;
+ private String expSuffix;
+ private Entities entities;
+ private List requiredZabbixItemKeys;
+ private List metrics;
+
+ @Override
+ public List extends RuleConfig> getMetricsRules() {
+ return metrics;
+ }
+
+ @Data
+ public static class Entities {
+ private List hostPatterns;
+ private List labels;
+ }
+
+ @Data
+ public static class EntityLabel {
+ private String name;
+ private String fromItem;
+ private String value;
+ }
+
+ @Data
+ public static class Metric implements RuleConfig {
+ private String name;
+ private String exp;
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/config/ZabbixConfigs.java b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/config/ZabbixConfigs.java
new file mode 100644
index 0000000000..9d5c5730f0
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/config/ZabbixConfigs.java
@@ -0,0 +1,71 @@
+/*
+ * 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.receiver.zabbix.provider.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.library.module.ModuleStartException;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+import org.apache.skywalking.oap.server.library.util.ResourceUtils;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+@Slf4j
+public class ZabbixConfigs {
+
+ public static List loadConfigs(String path, List fileNames) throws ModuleStartException {
+ if (CollectionUtils.isEmpty(fileNames)) {
+ return Collections.emptyList();
+ }
+
+ File[] configs;
+ try {
+ configs = ResourceUtils.getPathFiles(path);
+ } catch (FileNotFoundException e) {
+ throw new ModuleStartException("Load zabbix configs failed", e);
+ }
+
+ return Arrays.stream(configs).filter(File::isFile)
+ .map(f -> {
+ String fileName = f.getName();
+ int dotIndex = fileName.lastIndexOf('.');
+ fileName = (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
+ if (!fileNames.contains(fileName)) {
+ return null;
+ }
+ try (Reader r = new FileReader(f)) {
+ return new Yaml().loadAs(r, ZabbixConfig.class);
+ } catch (IOException e) {
+ log.warn("Reading file {} failed", f, e);
+ }
+ return null;
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/protocol/ZabbixErrorProtocolException.java b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/protocol/ZabbixErrorProtocolException.java
new file mode 100644
index 0000000000..55cbc4f440
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/protocol/ZabbixErrorProtocolException.java
@@ -0,0 +1,30 @@
+/*
+ * 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.receiver.zabbix.provider.protocol;
+
+/**
+ * Decode content is not the Zabbix protocol
+ */
+public class ZabbixErrorProtocolException extends Exception {
+
+ public ZabbixErrorProtocolException(final String message) {
+ super(message);
+ }
+
+}
\ No newline at end of file
diff --git a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/protocol/ZabbixProtocolDataCodec.java b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/protocol/ZabbixProtocolDataCodec.java
new file mode 100644
index 0000000000..0c6112cda1
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/protocol/ZabbixProtocolDataCodec.java
@@ -0,0 +1,27 @@
+/*
+ * 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.receiver.zabbix.provider.protocol;
+
+import io.netty.channel.CombinedChannelDuplexHandler;
+
+public class ZabbixProtocolDataCodec extends CombinedChannelDuplexHandler {
+ public ZabbixProtocolDataCodec() {
+ init(new ZabbixProtocolDecoder(), new ZabbixProtocolEncoder());
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/protocol/ZabbixProtocolDecoder.java b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/protocol/ZabbixProtocolDecoder.java
new file mode 100644
index 0000000000..e2d41d5080
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-zabbix-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/zabbix/provider/protocol/ZabbixProtocolDecoder.java
@@ -0,0 +1,117 @@
+/*
+ * 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.receiver.zabbix.provider.protocol;
+
+import com.google.common.base.Charsets;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.receiver.zabbix.provider.protocol.bean.ZabbixRequest;
+import org.apache.skywalking.oap.server.receiver.zabbix.provider.protocol.bean.ZabbixRequestJsonDeserializer;
+
+import java.util.List;
+
+@Slf4j
+public class ZabbixProtocolDecoder extends ByteToMessageDecoder {
+ private static final int HEADER_LEN = 9;
+ private static final byte[] PROTOCOL = new byte[] {'Z', 'B', 'X', 'D'};
+
+ private final Gson requestParser = new GsonBuilder()
+ .registerTypeAdapter(ZabbixRequest.class, new ZabbixRequestJsonDeserializer()).create();
+
+ @Override
+ protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List