Gah, this pull request thing totally didn't work out the way I'd expected it to 

tab indentations are all wrong, ide files got changed... if it's easier for you then just copy the changes, I don't care if I'm in the commit logs or not. You're welcome to adapt this however you want, I don't really care it's been useful so far though. It probably definitely could stand to get some more testing, and I am testing though I mainly just wanted to get this up here so I can get some idea of where to go with it, if anywhere. 

Description: 
A logger class that allows a user to attach a handler action; calls to the handler action are made asynchronously to prevent blocking. I'm confident in saything this is a good thing. 

Of course when you're dealing with threads there's a lot to take into account. Take a look at line 55 in RiakLogger.cs to see how it works.

I also added the ability to export data for debugging, namely so I could write a cURL request generator. I haven't been able to come up with a way that is particularly safe (other than to do a deep clone of the data that is passed which is annoying and I could care less because I trust myself better than that.) Currently to see how it works, take a look at RiakConnection.cs (you'll see that I called Debug() with an anonymous type as the first parameter as the carriage for various objects that I wanted to look at. 

Here's the code for using the debugger/logger. It's currently not the best example of a log handler but just to give you an idea, this is what I hoped to accomplish and to some degree have:

```
CorrugatedIron.RiakLogger.Instance.AddErrorLevel(RiakLogLevel.Debug);
			// may need to spend a lot of time looking for stuff in the debugger... 150 seconds
			CorrugatedIron.RiakLogger.Instance.SetAsyncCallbackTimeoutPeriod(150000);
			CorrugatedIron.RiakLogger.Instance.Output += (logdata) =>
			{
				//Notes:
				// A better way for people to use this thing would be to get what they need out of it into a concurrent queue 
				// and deal with it off thread since the max lifetime of the thread by default is 500 msecs
				try
				{
					// dump data if any
					if(logdata.debugging.Any(a => a.GetType().GetProperty("request") != null))
					{
						// Write message
						Log.WriteLine(logdata.level.ToString() + ": " + logdata.message);

						// parse payload
						foreach(object obj in logdata.debugging)
						{
							if(obj.GetType().GetProperty("request") != null)
							{
								// yay for extensions and dynamic
								var request = obj.ToDynamic().request;
								if(request.GetType() == typeof(CorrugatedIron.Messages.RpbSetBucketReq))
								{
									var rRequest = (CorrugatedIron.Messages.RpbSetBucketReq) request;
									string bucket = (rRequest.bucket != null) ? Encoding.Default.GetString(rRequest.bucket) : "";
									Log.WriteLine("(Riak SetBucketReq) | Bucket: " + bucket);
								}
								else if(request.GetType() == typeof(CorrugatedIron.Messages.RpbGetReq))
								{
									var rRequest = (CorrugatedIron.Messages.RpbGetReq) request;
									string bucket = (rRequest.bucket != null) ? Encoding.Default.GetString(rRequest.bucket) : "";
									string bucketType = (rRequest.type != null) ? Encoding.Default.GetString(rRequest.type) : "";
									string Rkey = (rRequest.key != null) ? Encoding.Default.GetString(rRequest.key) : "";
									Log.WriteLine("(Riak RpbGetReq) | Bucket: " 
										+ bucket 
										+ " | BucketType: " 
										+ bucketType
										+ " | Key: "
										+ Rkey);
								}
								else if(request.GetType() == typeof(CorrugatedIron.Messages.RpbIndexReq))
								{
									var rRequest = (CorrugatedIron.Messages.RpbIndexReq) request;
									string bucket = (rRequest.bucket != null) ? Encoding.Default.GetString(rRequest.bucket) : "";
									string bucketType = (rRequest.type != null) ? Encoding.Default.GetString(rRequest.type) : "";
									string index = (rRequest.index != null) ? Encoding.Default.GetString(rRequest.index) : "";
									string Rkey = (rRequest.key != null) ? Encoding.Default.GetString(rRequest.key) : "";
							
									Log.WriteLine("curl -vvv -X POST http://localhost:8098/types/"
										+ bucketType
										+ "/buckets/"
										+ bucket
										+ " -H 'riak-index-" + index + "-bin: " + Rkey +"'");
								}
								else
								{
									// Set a breakpoint here, look for stuff
									//request	{CorrugatedIron.Messages.RpbIndexReq}	CorrugatedIron.Messages.RpbIndexReq
								}
							}
						}
					}
				}
				catch(Exception ex)
				{
					// should always have try catch blocks in the log handler, otherwise the exception is caught 
					// in a try catch block in riak and is Console.Writelined.
					Log.WriteLine("Riak log handler exception: " + ex.Message);
				}
			};

```

to use that code you also need the dynamic extensions class I found... (I think on stackoverflow) 

```
public static class DynamicExtensions
	{
		public static dynamic ToDynamic(this object value)
		{
			IDictionary<string, object> expando = new ExpandoObject();

			foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
				expando.Add(property.Name, property.GetValue(value));

			return expando as ExpandoObject;
		}
	}
```

*It's been real useful to me so far, this is what it does:*

```
<Main>m__0 : Debug: protocol buffer WriteRead
----
<Main>m__0 : curl -vvv -X POST http://localhost:8098/types/UserData/buckets/SocialMedia2_erratic -H 'riak-index-ObjectType-bin: de.netcrave.Zombielet.ZombieletPost'
```

from the code: 

```
var streamClient = BackendManager.Instance.GetStreamStore();

			var indexResult = streamClient.GetSecondaryIndex(new RiakIndexId(
				SettingsManager.Instance.settings.StreamBucketType,
				SettingsManager.Instance.settings.StreamBucketName + "_" + username,
				"ObjectType"), t.ToString());
```

obviously trying to figure out how to generate a proper curl request and such still, but at least now I have a means to troubleshoot whats going on and figure out a solution.