using System; using System.Collections.Generic; using System.Net; using System.Threading.Tasks; using Aliyun.Acs.Dysmsapi.Model.V20170525; using Aliyun.Acs.Core; using Aliyun.Acs.Core.Profile; using TencentCloud.Common; using TencentCloud.Common.Profile; using TencentCloud.Sms.V20190711; using TencentCloud.Sms.V20190711.Models; using AliSendSmsRequest = Aliyun.Acs.Dysmsapi.Model.V20170525.SendSmsRequest; using AliSendSmsResponse = Aliyun.Acs.Dysmsapi.Model.V20170525.SendSmsResponse; using TxSendSmsRequest = TencentCloud.Sms.V20190711.Models.SendSmsRequest; using TxSendSmsResponse = TencentCloud.Sms.V20190711.Models.SendSmsResponse; using System.Net.Http; using LitJson; using System.Text; using System.Net.Http.Headers; namespace Sog { public class AppAlerter { private bool USE_TENCENT_CLOUD_SMS = true; private const int DEFAULT_ALERT_INTERVAL = 120; ServerApp m_app; string m_serverId; string m_smsMsg; string m_robotMsg; long m_crushUid; object m_locker = new object(); Dictionary m_lastSendSmsTimeDict = new Dictionary(); Dictionary m_lastSendRobotTimeDict = new Dictionary(); private long m_lastSendRobotTime; private int m_sendRobotCount; public AppAlerter(ServerApp app) { m_app = app; m_serverId = ServerIDUtils.IDToString(m_app.ServerID); } public void AlertException(Exception ex, long uid = 0) { lock (m_locker) { m_crushUid = uid; m_smsMsg = "exception: " + ex.Message; m_robotMsg = ex.Message + "\n" + ex.Source + "\n" + ex.StackTrace; TrySendSms(DEFAULT_ALERT_INTERVAL); TrySendRobot(DEFAULT_ALERT_INTERVAL); } } public void AlertMsg(string msg, int interval = DEFAULT_ALERT_INTERVAL, bool bOnlyRobot = false) { if(msg == null) { return; } lock (m_locker) { m_smsMsg = msg; m_robotMsg = msg; if (!bOnlyRobot) { TrySendSms(interval); } TrySendRobot(interval); } } private long GetLastSendSmsTime(string msg) { if(m_lastSendSmsTimeDict.ContainsKey(msg)) { return m_lastSendSmsTimeDict[msg]; } return 0; } private void SetLastSendSmsTime(string msg, long lastTime) { if (m_lastSendSmsTimeDict.ContainsKey(msg)) { m_lastSendSmsTimeDict[msg] = lastTime; } else { m_lastSendSmsTimeDict.Add(msg, lastTime); } } private long GetLastSendRobotTime(string msg) { if (m_lastSendRobotTimeDict.ContainsKey(msg)) { return m_lastSendRobotTimeDict[msg]; } return 0; } private void SetLastSendRobotTime(string msg, long lastTime) { if (m_lastSendRobotTimeDict.ContainsKey(msg)) { m_lastSendRobotTimeDict[msg] = lastTime; } else { m_lastSendRobotTimeDict.Add(msg, lastTime); } } private void TrySendSms(int interval) { if(m_app.AppParam.ServerConfig.alertPhoneNumber == null) { //TraceLog.Error("AppAlerter.TrySendSms alertPhoneNumber is null"); return; } if (m_app.AppParam.ServerConfig.alertPhoneNumber.Length == 0) { //TraceLog.Error("AppAlerter.TrySendSms alertPhoneNumber is 0"); return; } long now = m_app.Time.GetTimeSecond(); long lastTime = GetLastSendSmsTime(m_smsMsg); //每种类型的告警1分钟最多发一条短信 if (now - lastTime < interval) { return; } SetLastSendSmsTime(m_smsMsg, now); TraceLog.Error("AppAlerter.TrySendSms new task to send sms msg:{0}", m_smsMsg); Task sendTask = new Task(SendSmsTask); sendTask.Start(); } private void TrySendRobot(int interval) { if (!m_app.AppParam.ServerConfig.bWechatRobot) { //TraceLog.Error("AppAlerter.TrySendRobot bWechatRobot is false"); return; } if (String.IsNullOrEmpty(m_app.AppParam.ServerConfig.wechatRobotKey)) { //TraceLog.Error("AppAlerter.TrySendRobot wechatRobotKey is null"); return; } long now = m_app.Time.GetTimeSecond(); long lastTime = GetLastSendRobotTime(m_robotMsg); //每种类型的告警1分钟最多发一条短信 if (now - lastTime < interval) { return; } SetLastSendRobotTime(m_robotMsg, now); if (now - m_lastSendRobotTime > DEFAULT_ALERT_INTERVAL) { m_lastSendRobotTime = now; m_sendRobotCount = 0; } if (m_sendRobotCount >= 1) //限制发送次数 { //TraceLog.Error("AppAlerter.TrySendRobot m_sendWechatRobotCount is {0}", m_sendRobotCount); return; } m_sendRobotCount++; TraceLog.Trace("AppAlerter.TrySendRobot new task to send WechatRobot msg:{0}", m_robotMsg); Task sendTask = new Task(SendWechatRobotTask); sendTask.Start(); } private void SendSmsTask() { if (USE_TENCENT_CLOUD_SMS) { SendSmsTaskTencent(); } else { SendSmsTaskAli(); } } private void SendSmsTaskAli() { try { string product = "Dysmsapi";//短信API产品名称 string domain = "dysmsapi.aliyuncs.com";//短信API产品域名 string accessId = "LTAIwbt8GxIlFWa0"; string accessSecret = "qvGEdOJZB60Toq1YMgo5R4QuYTYmQZ"; string regionIdForPop = "cn-hangzhou"; IClientProfile profile = DefaultProfile.GetProfile(regionIdForPop, accessId, accessSecret); DefaultProfile.AddEndpoint(regionIdForPop, regionIdForPop, product, domain); IAcsClient acsClient = new DefaultAcsClient(profile); AliSendSmsRequest request = new AliSendSmsRequest(); request.PhoneNumbers = m_app.AppParam.ServerConfig.alertPhoneNumber[0]; request.SignName = "服务器告警"; request.TemplateCode = "SMS_25220245"; string preStr = m_app.AppParam.ServerConfig.alertMsgPre; if (preStr == null) { preStr = ""; } string json = "{\"serverid\":\"" + preStr + m_serverId + m_smsMsg + "\"}";//用于替换短信模板中的变量 request.TemplateParam = json; request.OutId = "xxxxxxxx"; //请求失败这里会抛ClientException异常 AliSendSmsResponse sendSmsResponse = acsClient.GetAcsResponse(request); if (sendSmsResponse == null) { TraceLog.Error("AppAlerter.SendSmsTaskAli SendSmsResponse null"); } else { TraceLog.Error("AppAlerter.SendSmsTaskAli SendSmsResponse code {0}", sendSmsResponse.Code); } } catch (Exception) { } } private void SendSmsTaskTencent() { try { Credential cred = new Credential { SecretId = "AKIDjdGdx1MK7vSjkWwmV7oGQJwKTLwioNpo", SecretKey = "wc9U0IcgvtazA6nEOfhV3PYPzJH1Yqqb" }; HttpProfile httpProfile = new HttpProfile(); httpProfile.Endpoint = ("sms.tencentcloudapi.com"); ClientProfile clientProfile = new ClientProfile(); clientProfile.HttpProfile = httpProfile; TxSendSmsRequest req = new TxSendSmsRequest(); req.SmsSdkAppid = "1400194039"; req.Sign = "紫晓互动"; req.PhoneNumberSet = m_app.AppParam.ServerConfig.alertPhoneNumber; // 模板618826, 参数: 机器{1} 进程{2} 发生错误{3} req.TemplateID = "618826"; req.TemplateParamSet = new string[] { GetAlertHostName(), m_serverId, m_smsMsg }; TraceLog.Trace("AppAlerter.SendSmsTaskTencent app {0} msg {1}", m_serverId, m_smsMsg); SmsClient client = new SmsClient(cred, "ap-guangzhou", clientProfile); TxSendSmsResponse res = client.SendSmsSync(req); TraceLog.Trace("AppAlerter.SendSmsTaskTencent res {0}", AbstractModel.ToJsonString(res)); } catch (Exception e) { TraceLog.Error(e.ToString()); TraceLog.Exception(e); } } private string GetAlertHostName() { string hostname = Dns.GetHostName(); //// 后续把hostname修改的直观一些, 就不用这么山寨了 //if (hostname == "VM-0-10-ubuntu") //{ // return "xjp"; // //return "119.28.105.46 xjp"; //} //if (hostname == "VM-0-11-ubuntu") //{ // return "US"; // //return "150.109.151.80 hk"; //} //if (hostname == "VM-34-242-ubuntu") //{ // return "guanzhou"; // //return "111.231.250.180 guanzhou"; //} ////短信有长度限制 //if (hostname != null && hostname.Length > 11) //{ // hostname = hostname.Substring(0, 11); //} return hostname; } private void SendWechatRobotTask() { HttpClient httpClient = null; try { string key = m_app.AppParam.ServerConfig.wechatRobotKey; if(key == null) { key = ""; return; } JsonData jbuilder = new JsonData(); //@人员 // JsonData mentioned_list = new JsonData(); // mentioned_list.Add("@all"); // jtext["mentioned_list"] = mentioned_list; //内容 string szcontent = $"hostname:{GetAlertHostName()}\nserverid:{m_serverId}msg:{m_robotMsg}"; if (m_crushUid != 0) { szcontent = $"hostname:{GetAlertHostName()}\nserverid:{m_serverId}\ncrushuid:{m_crushUid}\nmsg:{m_robotMsg}"; } string urlHead = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key="; //企业微信 if (m_app.AppParam.ServerConfig.robotMode == 1) //飞书 { urlHead = "https://open.feishu.cn/open-apis/bot/v2/hook/"; jbuilder["msg_type"] = "text"; JsonData jtext = new JsonData(); jtext["text"] = szcontent; jbuilder["content"] = jtext; } else { jbuilder["msgtype"] = "text"; JsonData jtext = new JsonData(); jtext["content"] = szcontent; jbuilder["text"] = jtext; } string szContent = jbuilder.ToJson(); string szurl = $"{urlHead}{key}"; TraceLog.Debug("http req {0}", szcontent); HttpContent content = null; string strutf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(szContent)); content = new StringContent(strutf8); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); httpClient = new HttpClient(); httpClient.MaxResponseContentBufferSize = 256000; httpClient.Timeout = TimeSpan.FromSeconds(10); HttpResponseMessage response = httpClient.PostAsync(new Uri(szurl), content).Result; if (response != null) { var result = response.Content.ReadAsStringAsync().Result; TraceLog.Trace("AppAlerter.SendWechatRobotTask result {0}", result.ToString()); } else { TraceLog.Error("AppAlerter.SendWechatRobotTask response is null"); } } catch (Exception ex) { TraceLog.Error("AppAlerter.SendWechatRobotTask ex {0}", ex.ToString()); } finally { if (httpClient != null) { httpClient.Dispose(); } } } } }