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

时间:2009-05-24 02:59:56

标签: c# web-services error-reporting error-logging

作为C#应用程序的作者,我发现如果我可以访问异常或调试日志,用户报告的故障排除问题会更容易。

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

我曾想过使用 SMTPClient 网络服务来发送信息。 SMTPClient可能无法正常工作,因为防火墙可能会阻止外发SMTP访问。 Web服务是否会出现发送大量数据(可能超过1 MB)的问题?

您建议将应用程序直接向开发人员传输错误报告以供审核的最佳方法是什么?

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

6 个答案:

答案 0 :(得分:3)

某种方式让用户知道你的意思。向他们询问代理,向他们询问电子邮件服务器,等等。

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

这是正确的。

答案 1 :(得分:3)

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

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

网络服务
好的

  • 每位用户没有特殊配置
  • 尺寸限制,可能超过5Mb-8MB的电子邮件

BAD

  • 公众可见(黑客喜欢玩 用这些东西)
  • 使用db back end创建Web服务的其他开发
  • 以后创建其他字段不好
  • 网络服务的变化并不好!

<强> SMTPClient
好的

  • 每位用户没有特殊配置
  • 登录公共文件夹可以轻松搜索/过滤(分组,...)
  • 所有可能发送的数据,屏幕截图,堆栈跟踪,用户设置,...
    - &GT; HTML
  • 记录格式和信息的变化很简单,因为我们使用了HTML电子邮件

BAD

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

答案 2 :(得分:2)

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

答案 3 :(得分:2)

我们使用3种方法

  • SMTP到专用邮箱。这需要很多的配置,并与“大公司”IT部门共舞,以确定他们的邮件服务器是什么以及如何对其进行身份验证并通过它进行发送。然后就有Norton Internet Security这样的程序可以阻止客户端计算机上的出站SMTP流量,从而在工作中投入额外的扳手。
  • 在我们的服务器上提交给asmx。这是我们首选的方法,但很多事情都会妨碍我们。它主要是代理,但诺顿也可以介入并打败你。如果涉及代理,请逃跑: - )
  • 使用HttpWebRequest和mime typ of multipart / form-encoded的HTTP POST。它也有代理和防火墙问题,但有时可以在asmx提交失败的情况下工作。
祝你好运。你是对的,如果你有堆栈跟踪,甚至可能是一个穷人老用户正在做的屏幕,那么很多更容易调试。

答案 4 :(得分:0)

我喜欢收到这样的电子邮件到专用邮箱。这样我就可以轻松归档,搜索或忽略它。

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

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

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

答案 5 :(得分:0)

如果您不希望在一天内发送许多报告......您可以创建一个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;
            }
        }
    }
}