通过 Internet 向开发人员发送应用程序错误和日志的最佳方式是啥?

Posted

技术标签:

【中文标题】通过 Internet 向开发人员发送应用程序错误和日志的最佳方式是啥?【英文标题】:What is the best way to send application errors and logs by internet to the developers?通过 Internet 向开发人员发送应用程序错误和日志的最佳方式是什么? 【发布时间】:2010-10-28 12:39:40 【问题描述】:

作为 C# 应用程序的作者,我发现如果我能够访问异常或调试日志,则对用户报告的问题进行故障排除会容易得多。

我已经包含了一个用户可以打开或关闭的本土日志记录机制。我希望用户能够通过 Internet 提交日志,以便我可以查看日志中的错误。

我曾考虑使用 SMTPClientWeb 服务 来发送信息。 SMTPClient 可能无法工作,因为防火墙可能会阻止传出 SMTP 访问。 Web 服务是否会在发送大量数据(可能超过 1 MB)时出现问题?

对于让应用程序将错误报告直接发送给开发人员进行审查的最佳方式,您会推荐什么?

编辑: 澄清:这是一个 Windows 应用程序,当发生错误时,我想打开一个对话框,要求提交错误。我的问题是关于通过互联网将错误日志从应用程序传输给我(开发人员)的机制。

【问题讨论】:

我喜欢 Dan 和 Peter 的答案,但必须选择一个接受。我都投了赞成票。 【参考方案1】:

以某种方式让用户知道您的意图。向他们索要代理,向他们索要电子邮件服务器,诸如此类。

如果他们发现您正在打开套接字或类似的东西并在没有通知的情况下发送数据,那么具有安全意识的人会非常紧张。

确实如此。

【讨论】:

【参考方案2】:

我建议不要发送所有内容(对您的应用程序的整个审核)。 但如果用户想要它(“反馈”按钮)或者如果应用程序中存在显式异常、致命错误、问题状态。

我们同时使用了 Web 服务和电子邮件 (SMTPClient)。我对这些的看法

网络服务 很好

每个用户没有特殊配置 大小限制,超过 5Mb-8MB 的电子邮件是可能的

不好

公开可见(黑客喜欢玩 用这些东西) 额外开发以创建带有 db 后端的 Web 服务 以后再创建额外的字段是不好的 Web 服务的更改不好!

SMTP客户端 很好

每个用户没有特殊配置 登录到公用文件夹使搜索/过滤变得容易(分组,...) 可以发送的所有数据、屏幕截图、堆栈跟踪、用户设置... --> html 日志格式和信息的更改很容易,因为我们使用了 HTML 电子邮件

不好

每个用户的特殊配置(smtp 服务器,电子邮件用户,...) 电子邮件大小限制 (5MB-8MB ??) 记录到电子邮件数据库需要大量开发

【讨论】:

【参考方案3】:

我们在我工作的地方使用 3 种方法

SMTP 到专用邮箱。这需要大量 配置,并与“大公司”IT 部门合作,以确定他们的邮件服务器是什么以及如何对其进行身份验证并通过它发送。然后还有像 Norton Internet Security 这样的程序可以阻止客户端计算机上的出站 SMTP 流量,这会导致额外的扳手工作。 提交到我们服务器上的 asmx。这是我们的首选方法,但有很多事情会妨碍您。它主要是代理,但诺顿也可以介入并击倒你。如果涉及代理,请逃跑:-) HTTP POST 使用 HttpWebRequest 和多部分/表单编码的 mime 类型。它还存在代理和防火墙问题,但有时可以在 asmx 提交失败的情况下工作。

祝你好运。你是对的,如果你有堆栈跟踪,甚至可能是可怜的老用户正在做什么的屏幕截图,那么调试起来会更容易。

【讨论】:

嗨 Dan F,我有一个带有 sql server 的应用程序。我打算将所有错误记录到数据库中,然后使用 sql server 数据库邮件一次性发送电子邮件,而不是发送即时电子邮件。欢迎您宝贵的cmets。 @Rauf 在这种情况下,我会考虑使用 SQL 服务器代理来排队发送电子邮件。将错误写入表,然后将消息(仅包含错误表中的 ID)发送到队列以将其发送。这样你就可以一次发送一个,每个之间有一个延迟。发送开始后,我将使用开始发送时间更新错误表中的行。如果它工作或失败,我也会用发送时间或发送失败时间更新原始错误表。【参考方案4】:

您可以自己编写,也可以使用 log4net 之类的东西,它会为您处理异常日志记录...

【讨论】:

请重新阅读问题;问题是“如何将日志信息传输给用户” @Steven:log4net 可用于使用例如 SmtpAppender 和适当的级别设置。 此外,Log4Net还有一个MulticastUdpAppender,这意味着如果你恰好在同一个子网上,你可以毫不费力地通过Log4Net客户端实时获取日志消息。【参考方案5】:

我喜欢将此类内容作为电子邮件发送到专用邮箱。这样我就可以轻松地归档、搜索或忽略它。

在客户端/发送方方面,我认为发送日志的弹出窗口是个好主意。如果是 windows,您可以使用 MAPI 发送电子邮件。在 unix 系统上,“邮件”问题适用于大多数系统。

您可以在确认消息中提示用户输入电子邮件地址,并可能提供一些发送方式的选项(包括复制/粘贴到他们选择的邮件客户端)。

您应该做的一件事是在未经用户许可的情况下发送信息。

【讨论】:

【参考方案6】:

如果您不希望在一天内发送这么多报告...您可以创建一个 gmail 帐户并使用它来发送电子邮件,以避免强制用户配置 SMTP 服务器。不确定 gmail 的条款和条件是什么。

这是我编写的一个类,它使用 gmail 帐户发送电子邮件...

显然这里存在一些安全问题,例如有人可能会访问您的 gmail 帐户。所以,考虑到这一点。

该类中有同步或异步发送电子邮件的方法。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Collections;
using System.Text;
using System.Net;
using System.Net.Mail;
using System.Net.Mime; 
//Mime is Not necerrary if you dont change the msgview and 
//if you dont add custom/extra headers 
using System.Threading;
using System.IO;
using System.Windows.Forms; // needed for MessageBox only.



namespace BR.Util

    public class Gmailer
    

        SmtpClient client = new SmtpClient();
        static String mDefaultToAddress = "yourToAddress@yourdomain.com";
        static String mDefaultFromAddress = "anonymous@gmail.com";
        static String mDefaultFromDisplayName = "Anonymous";

        String mGmailLogin = "someaccount@gmail.com";
        String mGmailPassword = "yourpassword";


        public Gmailer()
        
            client.Credentials = new System.Net.NetworkCredential(mGmailLogin, mGmailPassword);
            client.Port = 587;           
            client.Host = "smtp.gmail.com";
            client.EnableSsl = true;
            client.SendCompleted += new SendCompletedEventHandler(Gmailer_DefaultAsyncSendCompletedHandler);
        

        public void setSendCompletedHandler(SendCompletedEventHandler pHandler)
        
            client.SendCompleted -= Gmailer_DefaultAsyncSendCompletedHandler;
            client.SendCompleted += pHandler;
        

        /// <summary>
        /// Static method which sends an email synchronously.
        /// It uses a hardcoded from email.
        /// </summary>
        /// <returns></returns>
        public static bool quickSend(String toEmailAddress, String subject, String body)
        
            return Gmailer.quickSend(toEmailAddress, mDefaultFromAddress, mDefaultFromDisplayName, subject, body);
        

        /// <summary>
        /// Static method which sends an email synchronously.
        /// It uses the hardcoded email address.
        /// </summary>
        /// <returns>true if successful, false if an error occurred.</returns>
        public static bool quickSend(String toEmailAddress, String fromEmailAddress,
                                     String fromDisplayName, String subject, String body)
        
            try
            
                Gmailer gmailer = new Gmailer();
                System.Net.Mail.MailMessage mailMsg = gmailer.createMailMessage(toEmailAddress, fromEmailAddress, fromDisplayName, subject, body);
                gmailer.send(mailMsg);
            
            catch (Exception ex)
            
                return false;
            
            return true;
        

        // <summary> creates a MailMessage object initialized with the default values.</summary>
        public System.Net.Mail.MailMessage createMailMessage()
        
            return createMailMessage(mDefaultToAddress, mDefaultFromAddress, mDefaultFromDisplayName, mDefaultEmailSubject, mDefaultEmailBody);
        

        public System.Net.Mail.MailMessage createMailMessage(String toEmailAddress, String fromEmailAddress, 
                                                             String fromDisplayName, String subject, String body)
        
            //Build The MSG
            System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();
            msg.To.Add(toEmailAddress);
            msg.From = new MailAddress(fromEmailAddress, fromDisplayName, System.Text.Encoding.UTF8);
            msg.Subject = subject;
            msg.SubjectEncoding = System.Text.Encoding.UTF8;
            msg.Body = body;
            msg.BodyEncoding = System.Text.Encoding.UTF8;
            msg.IsBodyHtml = false;
            msg.Priority = MailPriority.High;
            return msg;
        

        public System.Net.Mail.MailMessage addAttachmentToMailMessage(System.Net.Mail.MailMessage msg, String attachmentPath)
        
            msg.Attachments.Add(new Attachment(attachmentPath));
            return msg;
        

        // <summary> method which blocks until the MailMessage has been sent.  Throws
        // System.Net.Mail.SmtpException if error occurs.</summary>
        public void send(System.Net.Mail.MailMessage pMailMessage)
        
            //try 
                client.Send(pMailMessage);
            //
            //catch (System.Net.Mail.SmtpException ex)
            //
            //    MessageBox.Show(ex.Message, "Send Mail Error");
            //
        

        // 
        public void sendAsync(System.Net.Mail.MailMessage pMailMessage)
        
            object userState = pMailMessage;
            try
            
                MailSent = false;
                client.SendAsync(pMailMessage, userState);
            
            catch (System.Net.Mail.SmtpException ex)
            
                MessageBox.Show(ex.Message, "Send Mail Error");
            
        

        // <summary> 
        // Provides a default SendComplete handler which is activated when an AsyncCompletedEvent 
        // is triggered by the private client variable.  This is useful for debugging etc.
        // Use the method setSendCompletedHandler to define your own application specific handler.
        // That method also turns this handler off.
        // </summary>
        public void Gmailer_DefaultAsyncSendCompletedHandler(object sender, AsyncCompletedEventArgs e)
        
            MailMessage mail = (MailMessage)e.UserState;
            string subject = mail.Subject;

            if (e.Cancelled)
            
                string cancelled = string.Format("[0] Send canceled.", subject);
                MessageBox.Show(cancelled);                
            
            if (e.Error != null)
            
                string error = String.Format("[0] 1", subject, e.Error.ToString());
                MessageBox.Show(error);                
            
            else
            
                MessageBox.Show("Message sent.");
            
            MailSent = true;
        


        private bool _MailSent = false;
        /// <summary>
        /// Set to false when an async send operation is started and is set to true when finished.
        /// </summary>
        public bool MailSent
        
            set
            
                _MailSent = value;
            
            get
            
                return _MailSent;
            
        
    

【讨论】:

以上是关于通过 Internet 向开发人员发送应用程序错误和日志的最佳方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章

PDO::__construct():服务器向客户端发送未知字符集 (255)。请向开发人员报告

使用浮动操作按钮向开发人员发送电子邮件 [关闭]

iOS代码签名错误

如何向开发者发送崩溃报告?

如何在 Jenkins 中向开发人员发送构建失败的电子邮件通知

Testflight beta 未向外部测试人员发送电子邮件或推送通知