Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Shortest Most Versatile Error Logging Ever

0.00/5 (No votes)
11 Oct 2016 1  
Simple but efficient way of logging errors over the internet using a PHP webservice/ REST and mail notification. Logging C#/ .NET errors over the web and with PHP and sending notification mail.

Introduction

The idea was to find a simple way to log different crashed applications over the internet and get notified by mail. Here is the simplest, shortest and most versatile way I found to do so.

Using the Code

You just need one C# class called WebEventLogger and one PHP file called errorproxy.php (see the code below). And, see the comments for changes to be made, e.g., your mail and url of the PHP file. The code was not worth uploading a whole project, so please use copy and paste. Wink

Usage is as simple as this:

using None;

//[...]

try
{
    // your code goes here
    // we throw an exception for testing purpose
    throw new Exception("test");
}
catch (Exception ex)
{
    WebEventLogger.LogToWebService(ex);
}

In the catch-block, the static method LogToWebService() is called to pass the reflected properties to the php- proxy, which sends the notification mail and stores a log file named after the assembly, where the error occurred, in the same folder (where you placed the PHP file) on the webspace.

E-Mail and Error.log may look like this (sample data):

01.07.12 10:20:00 Message from 11.100.200.250
Array
(
    [IPv4Internal] => 10.11.12.13
    [IPv6Internal] => ab00::1234:ccde:9876:r2d2
    [Message] => test
    [Data] => System.Collections.ListDictionaryInternal
    [TargetSite] => Void TEST_Error(System.String)
    [StackTrace] =>    bei None.Error(String test) in PathToError.cs:Line 9.
    [Source] => ErrorProject
)

Behind the Scenes

So here is the WebEventLogger.cs - copy this:

using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Net;

namespace None
{
    internal class WebEventLogger
    {
        /// <summary>
        /// Gets only headers from url e.g. used to pass parameters to 
        /// REST Services equivalent to GET-Method
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <returns>Returns 0 on Errors e.g. WebException</returns>
        public static HttpStatusCode GetHeaders(string url)
        {
            try
            {
                HttpStatusCode result = default(HttpStatusCode);
                var request = HttpWebRequest.Create(url);
                request.Method = "HEAD";
                using (var response = request.GetResponse() as HttpWebResponse)
                {
                    if (response != null)
                    {
                        result = response.StatusCode;
                        response.Close();
                    }
                }
                return result;
            }
            catch (Exception ex)
            {
                if (ex is WebException)
                {
                    //return ((HttpWebResponse)(ex as WebException).Response).StatusCode;
                    return 0;
                }
            }
            return 0;
        }

        /// <summary>
        /// Logs Exceptions to PHP web service proxy
        /// </summary>
        /// <param name="ex">The Exception</param>
        public static void LogToWebService(Exception ex)
        {
            //Helper.ShowMessageBoxOnOtherThread("Error occured: \n" + ex.Message);

            UriBuilder baseUri = new UriBuilder("http://path.to/errorproxy.php");
            NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);
            // note this is deprecated and may not work in the near future
            queryString["IPv4Internal"] = 
                      Dns.GetHostByName(Dns.GetHostName()).AddressList[0].ToString();
            queryString["IPv6Internal"] = 
                      Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString();
            foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(ex))
            {
                string name = descriptor.Name;
                object value = descriptor.GetValue(ex);
                if (!String.IsNullOrEmpty(name) && value != null)
                    queryString[name] = value.ToString();
            }
            string queryToAppend = queryString.ToString(); // Returns "key1=value1&key2=value2", 
                                                           // all URL-encoded
            if (baseUri.Query != null && baseUri.Query.Length > 1)
                baseUri.Query = baseUri.Query.Substring(1) + "&" + queryToAppend;
            else
                baseUri.Query = queryToAppend;

            // Call with Head
            if (GetHeaders(baseUri.Uri.AbsoluteUri) != HttpStatusCode.OK)
            {
                Console.WriteLine("Error Service not reachable!");
            }
        }
    }
}

And the PHP proxy called errorproxy.php - and copy that - which can be used on cheap hosting providers to fetch the error-log and send the notification e-mail. Watch encoding and file permissions on upload! Change the mail addresses and maybe the date format.

<?php
 # note this is german date format
 $body = date('d.m.y H:i:s')." Message from ".$_SERVER['REMOTE_ADDR']."\n".print_r($_REQUEST, True)."\n";
  # the error log file will be named after the assembly
 file_put_contents($_REQUEST['Source'].'.log', date('d.m.y H:i:s')." 
   Message from ".$_SERVER['REMOTE_ADDR']."\n".print_r($_REQUEST, True)."\n", FILE_APPEND);
 # the mail credentials, change sender and recipient adress
 $to = "my@mail.com";
  $subject = "Error in Application ".$_REQUEST['Source'];
  $from = "From: ".$_REQUEST['Source']." Error Logging <noreplay@mail.com>";
  mail($to, $subject, $body, $from);
 
  exit();
?>

History

  • 9th July, 2012: Uploaded

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here