[KARAF-6706] Add SNMP collector
diff --git a/assembly/src/main/feature/feature.xml b/assembly/src/main/feature/feature.xml
index 61d72d9..29fc430 100644
--- a/assembly/src/main/feature/feature.xml
+++ b/assembly/src/main/feature/feature.xml
@@ -241,6 +241,11 @@
         <bundle>mvn:org.apache.karaf.decanter.collector/org.apache.karaf.decanter.collector.jetty/${project.version}</bundle>
     </feature>
 
+    <feature name="decanter-collector-snmp" version="${project.version}" description="Karaf Decanter SNMP Collector">
+        <feature>decanter-common</feature>
+        <bundle>mvn:org.apache.karaf.decanter.collector/org.apache.karaf.decanter.collector.snmp/${project.version}</bundle>
+    </feature>
+
     <feature name="decanter-appender-log" version="${project.version}" description="Karaf Decanter Log Appender">
         <feature>decanter-common</feature>
         <configfile finalname="/etc/org.apache.karaf.decanter.appender.log.cfg">mvn:org.apache.karaf.decanter.appender/org.apache.karaf.decanter.appender.log/${project.version}/cfg</configfile>
diff --git a/collector/pom.xml b/collector/pom.xml
index dbecfb1..120b8dc 100644
--- a/collector/pom.xml
+++ b/collector/pom.xml
@@ -54,6 +54,7 @@
         <module>rest-servlet</module>
         <module>soap</module>
         <module>system</module>
+        <module>snmp</module>
         <module>socket</module>
         <module>prometheus</module>
         <module>jdbc</module>
diff --git a/collector/snmp/pom.xml b/collector/snmp/pom.xml
new file mode 100644
index 0000000..8db103c
--- /dev/null
+++ b/collector/snmp/pom.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-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">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.karaf.decanter</groupId>
+        <artifactId>collector</artifactId>
+        <version>2.6.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <groupId>org.apache.karaf.decanter.collector</groupId>
+    <artifactId>org.apache.karaf.decanter.collector.snmp</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: Decanter :: Collector :: SNMP</name>
+
+    <dependencies>
+        <!-- Still using 2.8.6 to work with JDK 8 -->
+        <dependency>
+            <groupId>org.snmp4j</groupId>
+            <artifactId>snmp4j</artifactId>
+            <version>2.8.6</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.decanter.collector</groupId>
+            <artifactId>org.apache.karaf.decanter.collector.utils</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <inherited>true</inherited>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Export-Package>
+                            !*
+                        </Export-Package>
+                        <Import-Package>
+                            !org.apache.karaf.decanter.collector.snmp,
+                            !org.snmp4j*,
+                            *
+                        </Import-Package>
+                        <Private-Package>
+                            org.apache.karaf.decanter.collector.snmp,
+                            org.apache.karaf.decanter.collector.utils,
+                            org.snmp4j*
+                        </Private-Package>
+                        <_dsannotations>*</_dsannotations>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/collector/snmp/src/main/java/org/apache/karaf/decanter/collector/snmp/SnmpPoller.java b/collector/snmp/src/main/java/org/apache/karaf/decanter/collector/snmp/SnmpPoller.java
new file mode 100644
index 0000000..6779680
--- /dev/null
+++ b/collector/snmp/src/main/java/org/apache/karaf/decanter/collector/snmp/SnmpPoller.java
@@ -0,0 +1,283 @@
+/*
+ * 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.karaf.decanter.collector.snmp;
+
+import org.apache.karaf.decanter.collector.utils.PropertiesPreparator;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.*;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.snmp4j.*;
+import org.snmp4j.event.ResponseEvent;
+import org.snmp4j.event.ResponseListener;
+import org.snmp4j.mp.MPv3;
+import org.snmp4j.mp.SnmpConstants;
+import org.snmp4j.security.*;
+import org.snmp4j.smi.*;
+import org.snmp4j.transport.DefaultTcpTransportMapping;
+import org.snmp4j.transport.DefaultUdpTransportMapping;
+import org.snmp4j.util.DefaultPDUFactory;
+import org.snmp4j.util.TreeEvent;
+import org.snmp4j.util.TreeUtils;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Component(
+        name = "org.apache.karaf.decanter.collector.snmp.poll",
+        immediate = true,
+        configurationPolicy = ConfigurationPolicy.REQUIRE,
+        property = { "decanter.collector.name=snmp",
+                "scheduler.period:Long=60",
+                "scheduler.concurrent:Boolean=false",
+                "scheduler.name=decanter-collector-snmp"
+        }
+)
+public class SnmpPoller implements ResponseListener, Runnable {
+
+    private final static Logger LOGGER = LoggerFactory.getLogger(SnmpPoller.class);
+
+    @Reference
+    private EventAdmin dispatcher;
+
+    private Dictionary<String, Object> configuration;
+    private boolean treeList;
+    private String oids;
+
+    private Address address;
+    private TransportMapping<? extends Address> transport;
+    private Snmp snmp;
+
+    private Target target;
+    private PDU pdu;
+
+    @Activate
+    public void activate(ComponentContext componentContext) throws Exception {
+        activate(componentContext.getProperties());
+    }
+
+    public void activate(Dictionary<String, Object> configuration) throws Exception {
+        this.configuration = configuration;
+
+        String addressConfig = (configuration.get("address") != null) ? (String) configuration.get("address") : "127.0.0.1/161";
+        this.address = GenericAddress.parse(addressConfig);
+
+        String protocol = (configuration.get("protocol") != null) ? (String) configuration.get("protocol") : "tcp";
+        if (protocol.equalsIgnoreCase("tcp")) {
+            this.transport = new DefaultTcpTransportMapping();
+        } else if (protocol.equalsIgnoreCase("udp")) {
+            this.transport = new DefaultUdpTransportMapping();
+        } else {
+            throw new IllegalStateException("Unknown SNMP protocol: " + protocol + " (udp and tcp are supported)");
+        }
+        int retries = (configuration.get("retries") != null) ? Integer.parseInt((String) configuration.get("retries")) : 2;
+        long timeout = (configuration.get("timeout") != null) ? Long.parseLong((String) configuration.get("timeout")) : 1500;
+        treeList = (configuration.get("treelist") != null) ? Boolean.parseBoolean((String) configuration.get("treelist")) : false;
+        oids = (configuration.get("oids") != null) ? (String) configuration.get("oids") : "";
+
+        this.snmp = new Snmp(transport);
+
+        int snmpVersion = (configuration.get("snmp.version") != null) ? Integer.parseInt((String) configuration.get("snmp.version")) : SnmpConstants.version3;
+        if (snmpVersion == SnmpConstants.version3) {
+            UserTarget userTarget = new UserTarget();
+
+            int securityLevel = (configuration.get("security.level") != null) ? Integer.parseInt((String) configuration.get("security.level")) : SecurityLevel.AUTH_PRIV;
+            userTarget.setSecurityLevel(securityLevel);
+            String securityName = (configuration.get("security.name") != null) ? (String) configuration.get("security.name") : "";
+            userTarget.setSecurityName(convertToOctetString(securityName));
+            userTarget.setAddress(address);
+            userTarget.setRetries(2);
+            userTarget.setTimeout(timeout);
+            userTarget.setVersion(snmpVersion);
+
+            this.target = userTarget;
+
+            USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
+            SecurityModels.getInstance().addSecurityModel(usm);
+
+            String authenticationProtocolConfig = (configuration.get("authentication.protocol") != null) ? (String) configuration.get("authentication.protocol") : "MD5";
+            OID authenticationProtocol = convertAuthenticationProtocol(authenticationProtocolConfig);
+
+            String authenticationPassphraseConfig = (configuration.get("authentication.passphrase") != null) ? (String) configuration.get("authentication.passphrase") : "";
+            OctetString authenticationPassphrase = convertToOctetString(authenticationPassphraseConfig);
+
+            String privacyProtocolConfig = (configuration.get("privacy.protocol") != null) ? (String) configuration.get("privacy.protocol") : "DES";
+            OID privacyProtocol = convertPrivacyProtocol(privacyProtocolConfig);
+
+            String privacyPassphraseConfig = (configuration.get("privacy.passphrase") != null) ? (String) configuration.get("privacy.passphrase") : "";
+            OctetString privacyPassphrase = convertToOctetString(privacyPassphraseConfig);
+
+            UsmUser user = new UsmUser(convertToOctetString(securityName), authenticationProtocol,
+                    authenticationPassphrase, privacyProtocol, privacyPassphrase);
+            usm.addUser(convertToOctetString(securityName), user);
+
+            ScopedPDU scopedPDU = new ScopedPDU();
+
+            String snmpContextEngineId = (configuration.get("snmp.context.engine.id") != null) ? (String) configuration.get("snmp.context.engine.id") : null;
+            if (snmpContextEngineId != null) {
+                scopedPDU.setContextEngineID(new OctetString(snmpContextEngineId));
+            }
+
+            String snmpContextName = (configuration.get("snmp.context.name") != null) ? (String) configuration.get("snmp.context.name") : null;
+            if (snmpContextName != null) {
+                scopedPDU.setContextName(new OctetString(snmpContextName));
+            }
+
+            this.pdu = scopedPDU;
+        } else {
+            CommunityTarget communityTarget = new CommunityTarget();
+            String snmpCommunity = (configuration.get("snmp.community") != null) ? (String) configuration.get("snmp.community") : "public";
+            communityTarget.setCommunity(convertToOctetString(snmpCommunity));
+            communityTarget.setAddress(address);
+            communityTarget.setRetries(retries);
+            communityTarget.setTimeout(timeout);
+            communityTarget.setVersion(snmpVersion);
+            this.target = communityTarget;
+            this.pdu = new PDU();
+        }
+        this.transport.listen();
+    }
+
+    @Deactivate
+    public void deactivate() throws Exception {
+        if (this.transport != null && this.transport.isListening()) {
+            this.transport.close();
+        }
+    }
+
+    @Override
+    public void run() {
+        this.pdu.clear();
+
+        this.pdu.setType(PDU.GETNEXT);
+
+        if (!treeList) {
+            for (String oid : oids.split(",")) {
+                this.pdu.add(new VariableBinding(new OID(oid)));
+            }
+        } else {
+            TreeUtils treeUtils = new TreeUtils(snmp, new DefaultPDUFactory());
+            for (String oid : oids.split(",")) {
+                List events = treeUtils.getSubtree(target, new OID(oid));
+                for (Object event : events) {
+                    TreeEvent treeEvent = (TreeEvent) event;
+                    if (treeEvent == null) {
+                        LOGGER.warn("SNMP event is null");
+                        continue;
+                    }
+                    if (treeEvent.isError()) {
+                        LOGGER.error("Error in SNMP event: {}", treeEvent.getErrorMessage());
+                        continue;
+                    }
+                    VariableBinding[] variableBindings = treeEvent.getVariableBindings();
+                    if (variableBindings == null || variableBindings.length == 0) {
+                        continue;
+                    }
+                    for (VariableBinding variableBinding : variableBindings) {
+                        if (variableBinding == null) {
+                            continue;
+                        }
+                        this.pdu.add(variableBinding);
+                    }
+                }
+            }
+        }
+        try {
+            snmp.send(pdu, target, null, this);
+        } catch (Exception e) {
+            LOGGER.warn("Can't send SNMP request", e);
+        }
+    }
+
+    @Override
+    public void onResponse(ResponseEvent event) {
+        ((Snmp) event.getSource()).cancel(event.getRequest(), this);
+
+        if (event.getRequest() == null || event.getResponse() == null) {
+            return;
+        }
+
+        PDU pdu = event.getResponse();
+        Map<String, Object> data = new HashMap<>();
+        data.put("type", "snmp.poll");
+        data.put("peerAddress", event.getPeerAddress());
+        try {
+            PropertiesPreparator.prepare(data, configuration);
+        } catch (Exception e) {
+            LOGGER.warn("Can't prepare event data", e);
+        }
+        // PDU v1 specific variables
+        if (pdu.getType() == PDU.V1TRAP) {
+            PDUv1 v1pdu = (PDUv1) pdu;
+            data.put("enterprise", v1pdu.getEnterprise().toString());
+            data.put("agentAddress", v1pdu.getAgentAddress().toString());
+            data.put("genericTrap", v1pdu.getGenericTrap());
+            data.put("specificTrap", v1pdu.getSpecificTrap());
+            data.put("timestamp", v1pdu.getTimestamp());
+        }
+        // all variables
+        for (VariableBinding variableBinding : pdu.getVariableBindings()) {
+            data.put(variableBinding.getOid().toString(), variableBinding.getVariable().toString());
+        }
+        // send event
+        dispatcher.postEvent(new Event("decanter/collector/snmp", data));
+    }
+
+    private OctetString convertToOctetString(String value) {
+        if (value == null) {
+            return null;
+        }
+        return new OctetString(value);
+    }
+
+    private OID convertAuthenticationProtocol(String authenticationProtocol) {
+        if (authenticationProtocol == null) {
+            return null;
+        }
+        if (authenticationProtocol.equals("MD5")) {
+            return AuthMD5.ID;
+        } else if (authenticationProtocol.equals("SHA1")) {
+            return AuthSHA.ID;
+        } else {
+            throw new IllegalArgumentException("Unknown authentication protocol: " + authenticationProtocol);
+        }
+    }
+
+    private OID convertPrivacyProtocol(String privacyProtocol) {
+        if (privacyProtocol == null) {
+            return null;
+        }
+        if (privacyProtocol.equals("DES")) {
+            return PrivDES.ID;
+        } else if (privacyProtocol.equals("TRIDES")) {
+            return Priv3DES.ID;
+        } else if (privacyProtocol.equals("AES128")) {
+            return PrivAES128.ID;
+        } else if (privacyProtocol.equals("AES192")) {
+            return PrivAES192.ID;
+        } else if (privacyProtocol.equals("AES256")) {
+            return PrivAES256.ID;
+        } else {
+            throw new IllegalArgumentException("Unknown privacy protocol: " + privacyProtocol);
+        }
+    }
+
+}
diff --git a/collector/snmp/src/main/java/org/apache/karaf/decanter/collector/snmp/SnmpTrap.java b/collector/snmp/src/main/java/org/apache/karaf/decanter/collector/snmp/SnmpTrap.java
new file mode 100644
index 0000000..a29cecf
--- /dev/null
+++ b/collector/snmp/src/main/java/org/apache/karaf/decanter/collector/snmp/SnmpTrap.java
@@ -0,0 +1,130 @@
+/*
+ * 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.karaf.decanter.collector.snmp;
+
+import org.apache.karaf.decanter.collector.utils.PropertiesPreparator;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.*;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.snmp4j.*;
+import org.snmp4j.mp.StateReference;
+import org.snmp4j.mp.StatusInformation;
+import org.snmp4j.smi.*;
+import org.snmp4j.transport.DefaultTcpTransportMapping;
+import org.snmp4j.transport.DefaultUdpTransportMapping;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component(
+        name = "org.apache.karaf.decanter.collector.snmp.trap",
+        immediate = true,
+        configurationPolicy = ConfigurationPolicy.REQUIRE
+)
+public class SnmpTrap implements CommandResponder {
+
+    private final static Logger LOGGER = LoggerFactory.getLogger(SnmpTrap.class);
+
+    @Reference
+    private EventAdmin dispatcher;
+
+    private Dictionary<String, Object> configuration;
+
+    private Address address;
+    private Snmp snmp;
+    private TransportMapping<? extends Address> transport;
+
+    @Activate
+    public void activate(ComponentContext componentContext) throws Exception {
+        activate(componentContext.getProperties());
+    }
+
+    public void activate(Dictionary<String, Object> configuration) throws Exception {
+        this.configuration = configuration;
+        String addressConfig = (configuration.get("address") != null) ? (String) configuration.get("address") : "127.0.0.1/161";
+        this.address = GenericAddress.parse(addressConfig);
+
+        String protocol = (configuration.get("protocol") != null) ? (String) configuration.get("protocol") : "tcp";
+        if (protocol.equalsIgnoreCase("tcp")) {
+            transport = new DefaultTcpTransportMapping((TcpAddress) address);
+        } else if (protocol.equalsIgnoreCase("udp")) {
+            transport = new DefaultUdpTransportMapping((UdpAddress) address);
+        } else {
+            throw new IllegalArgumentException("Unknown SNMP protocol: " + protocol + " (should be tcp or udp)");
+        }
+        this.snmp = new Snmp(transport);
+        this.snmp.addCommandResponder(this);
+        this.snmp.listen();
+    }
+
+    @Deactivate
+    public void deactivate() throws Exception {
+        transport.close();
+    }
+
+    @Override
+    public void processPdu(CommandResponderEvent event) {
+        PDU pdu = event.getPDU();
+        if (pdu != null) {
+            try {
+                if ((pdu.getType() != PDU.TRAP) && (pdu.getType() != PDU.V1TRAP) && (pdu.getType() != PDU.REPORT) && (pdu.getType() != PDU.RESPONSE)) {
+                    // respond the inform message
+                    pdu.setErrorIndex(0);
+                    pdu.setErrorStatus(0);
+                    pdu.setType(PDU.RESPONSE);
+                    StatusInformation statusInformation = new StatusInformation();
+                    StateReference reference = event.getStateReference();
+                    event.getMessageDispatcher().returnResponsePdu(event.getMessageProcessingModel(),
+                            event.getSecurityModel(),
+                            event.getSecurityName(),
+                            event.getSecurityModel(),
+                            pdu,
+                            event.getMaxSizeResponsePDU(),
+                            reference,
+                            statusInformation);
+                }
+                Map<String, Object> data = new HashMap<>();
+                data.put("type", "snmp.trap");
+                data.put("securityName", new OctetString(event.getSecurityName()));
+                data.put("peerAddress", event.getPeerAddress());
+                PropertiesPreparator.prepare(data, configuration);
+                // PDU v1 specific variables
+                if (pdu.getType() == PDU.V1TRAP) {
+                    PDUv1 v1pdu = (PDUv1) pdu;
+                    data.put("enterprise", v1pdu.getEnterprise().toString());
+                    data.put("agentAddress", v1pdu.getAgentAddress().toString());
+                    data.put("genericTrap", v1pdu.getGenericTrap());
+                    data.put("specificTrap", v1pdu.getSpecificTrap());
+                    data.put("timestamp", v1pdu.getTimestamp());
+                }
+                // all variables
+                for (VariableBinding variableBinding : pdu.getVariableBindings()) {
+                    data.put(variableBinding.getOid().toString(), variableBinding.getVariable().toString());
+                }
+                // send event
+                dispatcher.postEvent(new Event("decanter/collector/snmp", data));
+            } catch (Exception e) {
+                LOGGER.warn("Can't send SNMP event", e);
+            }
+        }
+    }
+
+}
diff --git a/manual/src/main/asciidoc/user-guide/collectors.adoc b/manual/src/main/asciidoc/user-guide/collectors.adoc
index ddc92c3..02a60f0 100644
--- a/manual/src/main/asciidoc/user-guide/collectors.adoc
+++ b/manual/src/main/asciidoc/user-guide/collectors.adoc
@@ -1086,6 +1086,70 @@
 
 The collector automatically registers in the Pax Web Jetty container and then all HTTP requests/responses data will be sent to the appenders.
 
+==== SNMP
+
+Decanter SNMP Collector allows you to trap or poll metrics from SNMP.
+
+The `decanter-collector-snmp` feature installs the SNMP collector:
+
+----
+karaf@root()> feature:install decanter-collector-snmp
+----
+
+Actually, this collector provides two kind of collectors: poller or trap.
+
+===== Trap
+
+If you want to use SNMP trap, you have to create `etc/org.apache.karaf.decanter.collector.snmp.trap.cfg` configuration file containing:
+
+----
+address=127.0.0.1:161
+protocol=tcp
+----
+
+* `address` is the listening SNMP trap address
+* `protocol` is the transport protocol (TCP or UDP).
+
+===== Poll
+
+If you want to use SNMP poller (periodically getting SNMP metrics), you have to create `etc/org.apache.karaf.decanter.collector.snmp.poll.cfg` configuration file containing:
+
+----
+address=127.0.0.1:161
+protocol=tcp
+retries=2
+timeout=1500
+treelist=false
+oids=first,second
+snmp.version=3
+security.level=3
+security.name=security
+authentication.protocol=MD5
+authentication.passphrase=pass
+privacy.protocol=DES
+privacy.passphrase=pass
+#snmp.context.engine.id=foo
+#snmp.context.name=foo
+snmp.community=public
+----
+
+* `address` is the SNMP service address
+* `protocol` is the transport protocol (tcp or udp)
+* `retries` is the number of attempts
+* `timeout` is the SNMP request timeout (in ms)
+* `treelist` is true to request SNMP tree, false else
+* `oids` is the list of SNMP OIDs to request
+* `snmp.version` is the SNMP version to use (3 by default)
+* `security.level` is the level of security expected by the SNMP version (3 == AUTH_PRIV by default)
+* `security.name` is the security name alias
+* `authentication.protocol` is the password protocol (MD5 or SHA1)
+* `authentication.passphrase` is the password/passphrase to use
+* `privacy.protocol` is DES, TRIDES, AES128, AES192, AES256
+* `private.passphrase` is the password/passphrase to use
+* `snmp.context.engine.id` is optional
+* `snmp.context.name` is optional
+* `snmp.community` is the community to use, `public` by default
+
 ==== Customizing properties in collectors
 
 You can add, rename or remove properties collected by the collectors before sending it to the dispatcher.
@@ -1111,4 +1175,4 @@
 
     ----
     fields.rename.helo=hello
-    ----
+    ----
\ No newline at end of file