Skip to content

Commit

Permalink
add smtp protocol and support smtp monitoring (#1407)
Browse files Browse the repository at this point in the history
Co-authored-by: 东风 <1335799468@qq.com>
  • Loading branch information
ZY945 and 东风 authored Dec 8, 2023
1 parent a7d1270 commit da62a76
Show file tree
Hide file tree
Showing 6 changed files with 342 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package org.dromara.hertzbeat.collector.collect.smtp;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.smtp.SMTP;
import org.dromara.hertzbeat.collector.collect.AbstractCollect;
import org.dromara.hertzbeat.collector.dispatch.DispatchConstants;
import org.dromara.hertzbeat.collector.util.CollectUtil;
import org.dromara.hertzbeat.common.constants.CollectorConstants;
import org.dromara.hertzbeat.common.constants.CommonConstants;
import org.dromara.hertzbeat.common.entity.job.Metrics;
import org.dromara.hertzbeat.common.entity.job.protocol.SmtpProtocol;
import org.dromara.hertzbeat.common.entity.message.CollectRep;
import org.dromara.hertzbeat.common.util.CommonUtil;

import java.io.IOException;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
* @author dongfeng
*/
@Slf4j
public class SmtpCollectImpl extends AbstractCollect {
public SmtpCollectImpl() {
}

@Override
public void collect(CollectRep.MetricsData.Builder builder, long monitorId, String app, Metrics metrics) {
long startTime = System.currentTimeMillis();
if (metrics == null || metrics.getSmtp() == null) {
builder.setCode(CollectRep.Code.FAIL);
builder.setMsg("Smtp collect must has Smtp params");
return;
}
SmtpProtocol smtpProtocol = metrics.getSmtp();
String host = smtpProtocol.getHost();
String port = smtpProtocol.getPort();
int timeout = CollectUtil.getTimeout(smtpProtocol.getTimeout());
SMTP smtp = null;
try {
smtp = new SMTP();
smtp.setConnectTimeout(timeout);
smtp.setCharset(StandardCharsets.UTF_8);
smtp.connect(host, Integer.parseInt(port));
if (smtp.isConnected()) {
long responseTime = System.currentTimeMillis() - startTime;
List<String> aliasFields = metrics.getAliasFields();

Map<String, String> resultMap = execCmdAndParseResult(smtp, smtpProtocol.getCmd(), smtpProtocol);
resultMap.put(CollectorConstants.RESPONSE_TIME, Long.toString(responseTime));
if (resultMap.size() < aliasFields.size()) {
log.error("smtp response data not enough: {}", resultMap);
builder.setCode(CollectRep.Code.FAIL);
builder.setMsg("The cmd execution results do not match the expected number of metrics.");
return;
}
CollectRep.ValueRow.Builder valueRowBuilder = CollectRep.ValueRow.newBuilder();
for (String field : aliasFields) {
String fieldValue = resultMap.get(field);
valueRowBuilder.addColumns(Objects.requireNonNullElse(fieldValue, CommonConstants.NULL_VALUE));
}
builder.addValues(valueRowBuilder.build());
} else {
builder.setCode(CollectRep.Code.UN_CONNECTABLE);
builder.setMsg("Peer connect failed,Timeout " + timeout + "ms");
return;
}
smtp.disconnect();
} catch (SocketException socketException) {
String errorMsg = CommonUtil.getMessageFromThrowable(socketException);
log.debug(errorMsg);
builder.setCode(CollectRep.Code.UN_CONNECTABLE);
builder.setMsg("The peer refused to connect: service port does not listening or firewall: " + errorMsg);
} catch (IOException ioException) {
String errorMsg = CommonUtil.getMessageFromThrowable(ioException);
log.info(errorMsg);
builder.setCode(CollectRep.Code.UN_CONNECTABLE);
builder.setMsg("Peer connect failed: " + errorMsg);
} catch (Exception e) {
String errorMsg = CommonUtil.getMessageFromThrowable(e);
log.warn(errorMsg, e);
builder.setCode(CollectRep.Code.FAIL);
builder.setMsg(errorMsg);
} finally {
if (smtp != null) {
try {
smtp.disconnect();
} catch (Exception e) {
log.warn(e.getMessage());
}
}
}
}

@Override
public String supportProtocol() {
return DispatchConstants.PROTOCOL_SMTP;
}

private static Map<String, String> execCmdAndParseResult(SMTP smtp, String cmd, SmtpProtocol smtpProtocol) throws IOException {
Map<String, String> result = new HashMap<>(8);
// 存入smtp连接的响应
result.put("smtpBanner", smtp.getReplyString());
smtp.helo(smtpProtocol.getEmail());
// 获取helo的响应
String replyString = smtp.getReplyString();
result.put("heloInfo", replyString);
String[] lines = replyString.split("\n");
for (String line : lines) {
if (line.startsWith("250")) {
result.put("response", "OK");
}
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public interface DispatchConstants {
* protocol telnet
*/
String PROTOCOL_TELNET = "telnet";
/**
* protocol smtp
*/
String PROTOCOL_SMTP = "smtp";
/**
* protocol udp
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ org.dromara.hertzbeat.collector.collect.mongodb.MongodbSingleCollectImpl
org.dromara.hertzbeat.collector.collect.snmp.SnmpCollectImpl
org.dromara.hertzbeat.collector.collect.ssh.SshCollectImpl
org.dromara.hertzbeat.collector.collect.telnet.TelnetCollectImpl
org.dromara.hertzbeat.collector.collect.smtp.SmtpCollectImpl
org.dromara.hertzbeat.collector.collect.ftp.FtpCollectImpl
org.dromara.hertzbeat.collector.collect.mq.RocketmqSingleCollectImpl
org.dromara.hertzbeat.collector.collect.udp.UdpCollectImpl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ public class Metrics {
* 使用telnet协议的监控配置信息
*/
private TelnetProtocol telnet;
/**
* Monitoring configuration information using the public smtp protocol
* 使用smtp协议的监控配置信息
*/
private SmtpProtocol smtp;
/**
* Use udp implemented by socket for service port detection configuration information
* 使用socket实现的udp进行服务端口探测配置信息
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.dromara.hertzbeat.common.entity.job.protocol;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* @author dongfeng
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SmtpProtocol {
/**
* email主机ip或域名
*/
private String host;

/**
* email主机端口
*/
private String port;

/**
* 超时时间
*/
private String timeout;

/**
* helo命令的测试者(email)
*/
private String email;

/**
* 发送的命令
*/
private String cmd;
}
172 changes: 172 additions & 0 deletions manager/src/main/resources/define/app-smtp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# 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.

# The monitoring type category:service-application service monitoring db-database monitoring mid-middleware custom-custom monitoring os-operating system monitoring
# 监控类型所属类别:service-应用服务 program-应用程序 db-数据库 custom-自定义 os-操作系统 bigdata-大数据 mid-中间件 webserver-web服务器 cache-缓存 cn-云原生 network-网络监控等等
category: service
# The monitoring type eg: linux windows tomcat mysql aws...
# 监控类型 eg: linux windows tomcat mysql aws...
app: smtp
# 监控类型国际化名称
name:
zh-CN: SMTP监控
en-US: SMTP MONITORS
# The description and help of this monitoring type
# 监控类型的帮助描述信息
help:
zh-CN: HertzBeat 对 SMTP 服务的(Banner,helo响应)相关指标进行监测。
en-US: HertzBeat monitors the banner and hello response related indicators of the SMTP service.
zh-TW: HertzBeat對SMTP服務的(Banner,helo響應)相關名額進行監測。
# 监控所需输入参数定义(根据定义渲染页面UI)
# Input params define for monitoring(render web ui by the definition)
params:
# field-param field key
# field-字段名称标识符
- field: host
# name-param field display i18n name
# name-参数字段显示名称
name:
zh-CN: SMTP的Host
en-US: Target Host
# type-param field type(most mapping the html input type)
# type-字段类型,样式(大部分映射input标签type属性)
type: host
# required-true or false
# 是否是必输项 true-必填 false-可选
required: true
# field-param field key
# field-字段名称标识符
- field: port
# name-param field display i18n name
# name-参数字段显示名称
name:
zh-CN: 端口
en-US: Port
# type-param field type(most mapping the html input type)
# type-字段类型,样式(大部分映射input标签type属性)
type: number
# when type is number, range is required
# 当type为number时,用range表示范围
range: '[0,65535]'
# required-true or false
# 是否是必输项 true-必填 false-可选
required: true
# default value 25
# 默认值 25
defaultValue: 25
# field-param field key
# field-字段名称标识符
- field: timeout
# name-param field display i18n name
# name-参数字段显示名称
name:
zh-CN: 连接超时时间(ms)
en-US: Connect Timeout(ms)
# type-param field type(most mapping the html input type)
# type-字段类型,样式(大部分映射input标签type属性)
type: number
# when type is number, range is required
# 当type为number时,用range表示范围
range: '[0,100000]'
# required-true or false
# 是否是必输项 true-必填 false-可选
required: true
# default value 6000
# 默认值 6000
defaultValue: 6000
# field-param field key
# field-字段名称标识符
- field: email
name:
zh-CN: email
en-US: email
type: text
# required-true or false
# 是否是必输项 true-必填 false-可选
required: true
# collect metrics config list
# 采集指标配置列表
metrics:
# metrics - summary
# 监控指标 - summary
- name: summary
i18n:
zh-CN: 概要
en-US: Summary
# metrics scheduling priority(0->127)->(high->low), metrics with the same priority will be scheduled in parallel
# priority 0's metrics is availability metrics, it will be scheduled first, only availability metrics collect success will the scheduling continue
# 指标采集调度优先级(0->127)->(优先级高->低) 优先级低的指标会等优先级高的指标采集完成后才会被调度, 相同优先级的指标会并行调度采集
# 优先级为0的指标为可用性指标,即它会被首先调度,采集成功才会继续调度其它指标,采集失败则中断调度
priority: 0
# 指标信息 包括 field名称 type字段类型:0-number数字,1-string字符串 label-是否是指标标签字段 unit:指标单位
# field-metric name, type-metric type(0-number,1-string), unit-metric unit('%','ms','MB'), label-whether it is a metrics label field
# field-指标名称, type-指标类型(0-number数字,1-string字符串), unit-指标单位('%','ms','MB'), label-是否是指标标签字段
fields:
- field: responseTime
type: 0
unit: ms
i18n:
zh-CN: 响应时间
en-US: ResponseTime
- field: response
type: 1
i18n:
zh-CN: 响应状态
en-US: Response
- field: smtpBanner
type: 1
i18n:
zh-CN: SMTP的Banner
en-US: SMTPBanner
- field: heloInfo
type: 1
i18n:
zh-CN: Helo日志
en-US: HeloInfo
# - field: emailMaxSize
# type: 0
# unit: byte
# i18n:
# zh-CN: 最大邮件大小
# en-US: EmailMaxSize
# - field: serverInfo
# type: 1
# i18n:
# zh-CN: 服务器相关信息
# en-US: ServerInfo
# - field: heloInfo
# type: 1
# i18n:
# zh-CN: Helo日志
# en-US: HeloInfo

# the protocol used for monitoring, eg: sql, ssh, http, telnet, wmi, snmp, sdk
# 采集协议, 目前支持sql, ssh, http, telnet, wmi, snmp, sdk
protocol: smtp
# Specific collection configuration when protocol is telnet protocol
# 当protocol为telnet协议时具体的采集配置
smtp:
# telnet host
# 远程登录主机
host: ^_^host^_^
# port
# 端口
port: ^_^port^_^
# timeout
# 超时时间
timeout: ^_^timeout^_^
# email
# email(helo命令所需)
email: ^_^email^_^

0 comments on commit da62a76

Please sign in to comment.