Skip to content

Instantly share code, notes, and snippets.

@bscheiman
Created May 5, 2013 07:46
Show Gist options
  • Save bscheiman/5520053 to your computer and use it in GitHub Desktop.
Save bscheiman/5520053 to your computer and use it in GitHub Desktop.
Raygun wrapper for MonoTouch / Xamarin.iOS
public static class Raygun {
private static string ApiKey { get; set; }
private static Uri BaseUrl = new Uri("https://api.raygun.io/entries");
[DllImport(MonoTouch.Constants.SystemLibrary)]
internal static extern int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string property, IntPtr output, IntPtr oldLen, IntPtr newp,
uint newlen);
public static void Attach(string apiKey) {
ApiKey = apiKey;
AppDomain.CurrentDomain.UnhandledException += (s, e) => {
Submit(e.ExceptionObject as Exception);
};
TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs e) => {
Submit(e.Exception);
};
}
private static string GetHardwareVersion() {
const string HardwareProperty = "hw.machine";
var pLen = Marshal.AllocHGlobal(sizeof(int));
sysctlbyname(HardwareProperty, IntPtr.Zero, pLen, IntPtr.Zero, 0);
var length = Marshal.ReadInt32(pLen);
if (length == 0) {
Marshal.FreeHGlobal(pLen);
return "Unknown";
}
var pStr = Marshal.AllocHGlobal(length);
sysctlbyname(HardwareProperty, pStr, pLen, IntPtr.Zero, 0);
var hardwareStr = Marshal.PtrToStringAnsi(pStr);
Marshal.FreeHGlobal(pLen);
Marshal.FreeHGlobal(pStr);
return hardwareStr;
}
public static void Submit(Exception ex) {
if (ex == null)
return;
if (string.IsNullOrEmpty(ApiKey)) {
Alert.Show("Raygun", "Empty API Key!");
return;
}
var ae = ex as AggregateException;
if (ae != null)
ex = ae.Flatten();
var hardware = GetHardwareVersion();
var version = NSBundle.MainBundle.ObjectForInfoDictionary("CFBundleVersion").ToString();
var message = new RaygunMessage {
occurredOn = DateTime.UtcNow.ToString("o"),
details = new Details {
machineName = hardware,
version = version,
client = new Client {
name = hardware,
version = version
},
error = GetErrorFromException(ex)
}
};
using (var wc = new WebClient()) {
wc.Encoding = Encoding.UTF8;
wc.Headers[HttpRequestHeader.ContentType] = "application/json";
wc.Headers.Add("X-ApiKey", ApiKey);
wc.UploadStringAsync(BaseUrl, "POST", message.ToJson());
}
}
static List<StackTrace> BuildStackTrace(Exception ex) {
var list = new List<StackTrace>();
var stackTrace = new System.Diagnostics.StackTrace(ex, true);
var frames = stackTrace.GetFrames();
if (frames == null || frames.Length == 0) {
list.Add(new StackTrace { fileName = "none", lineNumber = 0 });
return list;
}
foreach (var frame in frames) {
var method = frame.GetMethod();
if (method != null) {
int lineNumber = frame.GetFileLineNumber();
if (lineNumber == 0)
lineNumber = frame.GetILOffset();
var methodName = GenerateMethodName(method);
string file = frame.GetFileName();
string className = method.ReflectedType != null ? method.ReflectedType.FullName : "(unknown)";
var line = new StackTrace {
fileName = file,
lineNumber = lineNumber,
methodName = methodName,
className = className
};
list.Add(line);
}
}
return list;
}
private static string GenerateMethodName(MethodBase method) {
var sb = new StringBuilder();
sb.Append(method.Name);
if (method is MethodInfo && method.IsGenericMethod) {
Type[] genericArguments = method.GetGenericArguments();
sb.Append("[");
int index2 = 0;
bool flag2 = true;
for (; index2 < genericArguments.Length; ++index2) {
if (!flag2)
sb.Append(",");
else
flag2 = false;
sb.Append(genericArguments[index2].Name);
}
sb.Append("]");
}
sb.Append("(");
ParameterInfo[] parameters = method.GetParameters();
bool flag3 = true;
for (int index2 = 0; index2 < parameters.Length; ++index2) {
if (!flag3)
sb.Append(", ");
else
flag3 = false;
string str2 = "<UnknownType>";
if (parameters[index2].ParameterType != null)
str2 = parameters[index2].ParameterType.Name;
sb.Append(str2 + " " + parameters[index2].Name);
}
sb.Append(")");
return sb.ToString();
}
private static Error GetErrorFromException(Exception ex) {
var exceptionType = ex.GetType();
var error = new Error {
message = string.Format("{0}: {1}", exceptionType.Name, ex.Message),
stackTrace = BuildStackTrace(ex),
className = exceptionType.FullName,
data = ex.Data
};
if (ex.InnerException != null)
error.innerError = GetErrorFromException(ex.InnerException);
return error;
}
public class Client {
public string name { get; set; }
public string version { get; set; }
public string clientUrl { get; set; }
}
public class StackTrace {
public int lineNumber { get; set; }
public string className { get; set; }
public string fileName { get; set; }
public string methodName { get; set; }
}
public class Error {
public Error innerError { get; set; }
public IDictionary data { get; set; }
public string className { get; set; }
public string message { get; set; }
public List<StackTrace> stackTrace { get; set; }
}
public class Details {
public string machineName { get; set; }
public string version { get; set; }
public Client client { get; set; }
public Error error { get; set; }
}
public class RaygunMessage {
public string occurredOn { get; set; }
public Details details { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment