Format Log File

In almost all projects we have to implement some kind of logging mechanism which facilitates us in finding the root cause of the issue and application health. However generally I believe that log files are not properly formatted due to which we need to spend more time in understanding our log files.

So, finally I have written a small class to format complex object into well formatted log file. Also it uses word wrap on columns of log to ensure readable format. Here is how log files look before:-


And here is how log look after properly formatted:-

Here is code which I used to format my log:-

   1:      public class LogFormatter 
   2:      {
   3:          private static string DefaultNameSpace = ConfigurationManager.AppSettings["Log.DefaultNameSpace"];
   4:          /// <summary>
   5:          /// Formats the object as string.
   6:          /// </summary>
   7:          /// <param name="obj">The obj.</param>
   8:          /// <returns></returns>
   9:          private static string FormatTypeAsString(object obj)
  10:          {
  11:              StringBuilder sb = new StringBuilder(1024);
  12:   
  13:              if (obj is string || obj is Exception || obj is DbCommand || obj is DateTime || obj is TimeSpan || obj == null)
  14:              {
  15:   
  16:              }
  17:              else
  18:              {
  19:                  sb.Append("[Type:" + obj.GetType().ToString() + "]");
  20:              }
  21:   
  22:              if (obj == null)
  23:              {
  24:                  sb.Append("Value: Null");
  25:              }
  26:              else if (obj is string)
  27:              {
  28:                  sb.Append((string)obj);
  29:              }
  30:              else if (obj is DateTime)
  31:              {
  32:                  sb.Append(((DateTime)obj).ToString("dd-MMM-yyyy hh:mm:ss tt"));
  33:              }
  34:              else if (obj is TimeSpan)
  35:              {
  36:                  sb.Append(((TimeSpan)obj).FormatAsString());
  37:              }
  38:              else if (obj is DbCommand)
  39:              {
  40:                  DbCommand cmd = (DbCommand)obj;
  41:                  string commandDetail = string.Empty;
  42:                  commandDetail = cmd.CommandType.ToString();
  43:   
  44:                  if (cmd.Connection != null)
  45:                  {
  46:                      commandDetail += "(" + cmd.Connection.DataSource + ")";
  47:                  }
  48:   
  49:                  sb.Append(" CommandText=[" + cmd.CommandText + "] CommandDetail=[" + commandDetail + "] Parameters= [");
  50:   
  51:                  foreach (DbParameter param in cmd.Parameters)
  52:                  {
  53:                      string paramValue = "null";
  54:                      if (param.Value != null)
  55:                      {
  56:                          paramValue = param.Value.ToString();
  57:                      }
  58:   
  59:                      sb.Append("@" + param.ParameterName + "=" + paramValue + " ");
  60:                  }
  61:                  sb.Append("]");
  62:              }
  63:              else if (obj is Exception)
  64:              {
  65:                  sb.Append(" Exception=[" + obj.ToString().Replace("\r", "").Replace("\n", "\t") + "] Details=[" +
  66:                  ((Exception)obj).StackTrace.Replace("\r", "").Replace("\n", "\t") + "]");
  67:              }
  68:              else
  69:              {
  70:                  var type = obj.GetType();
  71:   
  72:                  foreach (var prop in type.GetProperties())
  73:                  {
  74:                      var val = prop.GetValue(obj, new object[] { });
  75:   
  76:                      var valStr = string.Empty;
  77:                      if (val != null)
  78:                      {
  79:                          if (prop.PropertyType == typeof(DateTime))
  80:                          {
  81:                              valStr = ((DateTime)val).ToString("dd-MMM-yyyy hh:mm:ss tt");
  82:                          }
  83:                          else if (prop.PropertyType == typeof(TimeSpan))
  84:                          {
  85:                              valStr = ((TimeSpan)val).FormatAsString();
  86:                          }
  87:                          else
  88:                          {
  89:                              valStr = val.ToString();
  90:                          }
  91:                          sb.Append("[" + prop.Name + ":" + valStr + "]");
  92:                      }
  93:                  }
  94:              }
  95:              return sb.ToString();
  96:          }
  97:   
  98:          /// <summary>
  99:          /// Formats the log.
 100:          /// </summary>
 101:          /// <param name="eventName">Name of the event.</param>
 102:          /// <param name="details">The details.</param>
 103:          /// <returns></returns>
 104:          public string FormatLog(string eventName, object details, DateTime logDate)
 105:          {
 106:              int eventLength = 30;
 107:              int methodLength = 60;
 108:              int typeDetailLength = 80;
 109:              List<string> eventList = WordWrap(eventName, eventLength);
 110:              List<string> methodList = WordWrap(GetMethodNameFromStackTrace(), methodLength);
 111:              List<string> typeDetailList = WordWrap(FormatTypeAsString(details), typeDetailLength);
 112:   
 113:              StringBuilder sb = new StringBuilder();
 114:   
 115:              int maxCount = eventList.Count;
 116:              if (methodList.Count > maxCount)
 117:              {
 118:                  maxCount = methodList.Count;
 119:              }
 120:              else if (typeDetailList.Count > maxCount)
 121:              {
 122:                  maxCount = typeDetailList.Count;
 123:              }
 124:   
 125:              for (int i = 0; i < maxCount; i++)
 126:              {
 127:                  sb.Append("\r\n");
 128:   
 129:                  string line = string.Format("{0,-23}|{1,-" + eventLength + "}|{2,-" + methodLength + "}|{3,-" + typeDetailLength + "}|",
 130:                      (i == 0) ? logDate.ToString("dd-MMM-yyy hh:mm:ss tt") : string.Empty,
 131:                      GetValueFromList(eventLength, eventList, i),
 132:                      GetValueFromList(methodLength, methodList, i),
 133:                      GetValueFromList(typeDetailLength, typeDetailList, i));
 134:   
 135:                  sb.Append(line);
 136:              }
 137:   
 138:              return sb.ToString();
 139:          }
 140:   
 141:          /// <summary>
 142:          /// Gets the value from list.
 143:          /// </summary>
 144:          /// <param name="maxLength">Length of the max.</param>
 145:          /// <param name="list">The list.</param>
 146:          /// <param name="index">The index.</param>
 147:          /// <returns></returns>
 148:          private string GetValueFromList(int maxLength, List<string> list, int index)
 149:          {
 150:              string result = string.Empty;
 151:              if (index < list.Count)
 152:              {
 153:                  result = list[index];
 154:              }
 155:              else
 156:              {
 157:                  result = new string(' ', maxLength);
 158:              }
 159:              return result;
 160:          }
 161:   
 162:          /// <summary>
 163:          /// Words the wrap.
 164:          /// </summary>
 165:          /// <param name="text">The text.</param>
 166:          /// <param name="width">The width.</param>
 167:          /// <returns></returns>
 168:          private List<string> WordWrap(string text, int width)
 169:          {
 170:              List<string> list = new List<string>();
 171:              StringBuilder sb = new StringBuilder();
 172:   
 173:              if (text.Length < width)
 174:              {
 175:                  list.Add(text);
 176:              }
 177:              else
 178:              {
 179:   
 180:                  for (int i = 0; i < text.Length; i++)
 181:                  {
 182:                      if (i % width == 0 && i != 0)
 183:                      {
 184:                          list.Add(sb.ToString());
 185:                          sb = new StringBuilder();
 186:                      }
 187:   
 188:                      sb.Append(text[i]);
 189:                  }
 190:                  list.Add(sb.ToString());
 191:              }
 192:              return list;
 193:          }
 194:   
 195:          /// <summary>
 196:          /// Gets the name of the method from StackTrace.
 197:          /// </summary>
 198:          /// <returns></returns>
 199:          private string GetMethodNameFromStackTrace()
 200:          {
 201:              try
 202:              {
 203:                  var method = new StackFrame(4, true).GetMethod();
 204:                  string methodName = method.DeclaringType.ToString() + "." + method.Name + "()";
 205:                  methodName = methodName.Replace(DefaultNameSpace, "");
 206:                  return methodName;
 207:              }
 208:              catch //(Exception ex)
 209:              {
 210:                  //Suppress Exception
 211:              }
 212:              return string.Empty;
 213:          }
 214:      }

Happy Coding !!!

Download Image from URL with c#

Recently I came across a situation where I need to download Images from a web site. Here is a tiny little code through which I have done that. I am sharing it for your reference.
/// 
/// Downloads the image from URL.
/// 
/// "imageUrl">The image URL.
/// "imagePath">The image path.
public void  DownloadImageFromUrl(string imageUrl,string imagePath)
{
    try
    {
        System.Net.HttpWebRequest httpWebRequest = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(imageUrl);
        httpWebRequest.AllowWriteStreamBuffering = true;
        httpWebRequest.Timeout = 30000;
 
        using (System.Net.WebResponse webResponse = httpWebRequest.GetResponse())
        {
            System.IO.Stream stream = webResponse.GetResponseStream();
            System.Drawing.Image image = System.Drawing.Image.FromStream(stream);
            image.Save(imagePath);
        }
    }
    catch (Exception ex)
    {
        //Do some Exception Handling There
    } 
}
Here is how you can call above function
string downloadPath = "d:\\test.jpg";
DownloadImageFromUrl("http://test.com/test/test.ashx?ImageID=" + x + ".jpg", downloadPath); 
Happy Coding !!!

Random Password Generator with optional combination of Lower, Upper, Special and Numeric characters

This is been quite some time since I have shared some useful stuff with community. As you all know priorities always keep changing. So here is another simple utility class to generate random password.

You can define the minimum numbers of characters in your password string as well. This can be very useful if you have strict requirements for password security. As many password policy restrict user to set a password with sufficient complexity so that no one can brute force it easily.

This class uses double randomization algorithm to ensure that passwords don't get repeated. First it randomly picks the characters into a buffer. Once done, it does random swapping of all elements on buffer to ensure randomness of password.
Here is how you can utilize this code:-
/*
    * Author: Zeeshan Muar
    * Version: 1.0
    * This program is free software: you can redistribute it and/or modify
    * it under the terms of the GNU General Public License as published by
    * the Free Software Foundation, either version 3 of the License, or
    * (at your option) any later version.
    * 
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    * GNU General Public License for more details.
    * 
    * You should have received a copy of the GNU General Public License
    * along with this program.  If not, see .
*/
public sealed class PasswordEngine
{
    private static PasswordEngine engine = new PasswordEngine();
 
    public static PasswordEngine Default
    {
        get
        {
            return engine;
        }
    }
        
    private readonly Random rnd = new Random();
    private string[] allowedCharacters = new string[]
    {
        "abcdefghijklmnopqrstuvwxyz",
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
        "1234567890",
        "!@#$%^&*()_"
    };
 
    public string Generate(int size)
    {
        return Generate(size, 0, 0, 0);
    }
 
    public string Generate(int size,  int minCapitalLetters, int minNumbers, int minSpecial)
    {
        //Parameter validation
        if (minCapitalLetters + minNumbers + minSpecial > size)
        {
            throw new Exception("Parameter size should be less than or equal to minCapitalLetters + minSmallLetters + minNumbers + minSpecial");
        }
 
 
        //Buffer for 
        char[] buffer = new char[size];
 
        int currentIndex = 0;
        //Fill Capital Letters
        currentIndex = FillBuffer(currentIndex, minCapitalLetters, 1, buffer);
        //Fill Numbers Characters
        currentIndex = FillBuffer(currentIndex, minNumbers, 2, buffer);
        //Fill Special Characters
        currentIndex = FillBuffer(currentIndex, minSpecial, 3, buffer);
 
        //Fill remaining buffer with small characters
        int minSmallLetters= size - (minCapitalLetters  + minNumbers + minSpecial);
        currentIndex = FillBuffer(currentIndex, minSmallLetters, 0, buffer);
 
        RandomizeBuffer(size, buffer);
 
        return new string(buffer);
    }
 
    private void RandomizeBuffer(int size, char[] buffer)
    {
        for (int i = 0; i < size; i++)
        {
            char source = buffer[i];
            int swapIndex = rnd.Next(size);
            buffer[i] = buffer[swapIndex];
            buffer[swapIndex] = source;
        }
    }
 
    private int FillBuffer(int startIndex, int count, int row, char[] buffer)
    {
        for (int i = 0; i < count; i++)
        {
            rnd.Next(3);
            int col = rnd.Next(allowedCharacters[row].Length);
 
            buffer[i+startIndex] = allowedCharacters[row][col];
        }
 
        return startIndex + count;
    }
}

Here is how you can call this class to generate random passwords:-
//This will generate a simple password
string password1 = PasswordEngine.Default.Generate(10);
 
//This will generate a password with 2 numbers, 2 special and 2 capital letters
string password2 = PasswordEngine.Default.Generate(10, 2, 2, 2);

Feel free to discuss, Happy Coding !!!