public static ErrorReporter.OnError createSendOnError( string loggerName, Uri reportingUrl, ApiKeys keys, ErrorReporter.AppInfo appInfo, ExtraData addExtraData, bool onlySendUniqueErrors ) { var sentJsonsOpt = onlySendUniqueErrors.opt(() => new HashSet <string>()); return(data => { var msg = message(loggerName, keys, appInfo, data, addExtraData); Action send = () => ASync.NextFrame(() => msg.send(reportingUrl)); sentJsonsOpt.voidFold( send, sentJsons => { if (sentJsons.Add(msg.json)) { send(); } else if (Log.isDebug) { Log.rdebug($"Not sending duplicate Sentry msg: {msg}"); } } ); }); }
public static Message message( SentryAPI.ApiKeys keys, ErrorReporter.AppInfo appInfo, LogEvent data, SentryAPI.ExtraData extraData, Option <SentryAPI.UserInterface> userOpt, IDictionary <string, SentryAPI.Tag> staticTags ) { const string logger = "tlplib-" + nameof(SentryRESTAPI); var eventId = Guid.NewGuid(); var timestamp = DateTime.UtcNow; // The list of frames should be ordered by the oldest call first. var stacktraceFrames = data.entry.backtrace.map( // ReSharper disable once ConvertClosureToMethodGroup - MCS bug b => b.elements.a.Select(a => backtraceElemToJson(a)).Reverse().ToList() ); // Beware of the order! Do not mutate static tags! var tags = SentryAPI.dynamicTags() .addAll(staticTags) .addAll(SentryAPI.convertTags(data.entry.tags)); extraData.addTagsToDictionary(tags); // Extra contextual data is limited to 4096 characters. var extras = SentryAPI.dynamicExtras() .addAll(SentryAPI.convertExtras(data.entry.extras)); extraData.addExtrasToDictionary(extras); var json = new Dictionary <string, object> { { "message", s(data.entry.message) }, { "level", s(data.level.asSentry(), SentryAPI.LogLevel_.str) }, { "logger", s(logger) }, { "platform", s(Application.platform.ToString()) }, { "release", s(appInfo.bundleVersion) }, { "tags", tags.toDict(_ => _.Key, _ => _.Value.s) }, { "extra", extras }, { "fingerprint", data.entry.toSentryFingerprint() } }; foreach (var stacktrace in stacktraceFrames) { json.Add("stacktrace", new Dictionary <string, object> { { "frames", stacktrace } }); } foreach (var user in userOpt) { json.Add("user", userInterfaceParametersJson(user)); } return(new Message(keys, eventId, timestamp, json)); }
public static ErrorReporter.OnError createEditorOnError( string apiKey, ErrorReporter.AppInfo appInfo ) { return(data => ASync.NextFrame(() => { if (Log.isInfo) { Log.info("Airbrake error:\n\n" + data + "\n" + xml(apiKey, appInfo, data)); } })); }
public SendOnErrorData( ErrorReporter.AppInfo appInfo, ExtraData addExtraData, Option <UserInterface> userOpt, IDictionary <string, Tag> staticTags, IDictionary <string, string> staticExtras ) { this.appInfo = appInfo; this.addExtraData = addExtraData; this.userOpt = userOpt; this.staticTags = staticTags; this.staticExtras = staticExtras; }
public static AirbrakeXML xml( string apiKey, ErrorReporter.AppInfo appInfo, ErrorReporter.ErrorData data ) { var doc = new XmlDocument(); var dec = doc.CreateXmlDeclaration("1.0", "UTF-8", null); doc.AppendChild(dec); // Required. The version of the API being used. Should be set to "2.3" var root = doc.CreateElement("notice"); doc.AppendChild(root); root.SetAttribute("version", "2.3"); // Required. The API key for the project that this error belongs to. // The API key can be found by viewing the edit project form on the Airbrake site. root.AppendChild(doc.textElem("api-key", apiKey)); root.AppendChild(doc.CreateElement("notifier")).tap(notifier => { notifier.AppendChild(doc.textElem("name", "tlplib")); notifier.AppendChild(doc.textElem("version", "1.0")); notifier.AppendChild(doc.textElem("url", "https://github.com/tinylabproductions/tlplib")); }); root.AppendChild(doc.CreateElement("server-environment").tap(env => { env.AppendChild(doc.textElem( "environment-name", Debug.isDebugBuild ? "debug" : "production" )); env.AppendChild(doc.textElem("app-version", appInfo.bundleVersion.asString)); })); root.AppendChild(doc.CreateElement("error").tap(err => { err.AppendChild(doc.textElem("class", data.errorType.ToString())); err.AppendChild(doc.textElem("message", data.message)); err.AppendChild(doc.CreateElement("backtrace").tap(xmlBt => { foreach (var btElem in data.backtrace) { xmlBt.AppendChild(doc.backtraceElem(btElem)); } })); })); root.AppendChild(doc.CreateElement("request").tap(req => { req.AppendChild(doc.textElem("url", appInfo.bundleIdentifier)); req.AppendChild(doc.textElem("component", "")); })); return(new AirbrakeXML(doc)); }
public static ErrorReporter.OnError createLogOnError( string loggerName, DSN dsn, ErrorReporter.AppInfo appInfo, ExtraData addExtraData ) { return(data => ASync.NextFrame(() => { if (Log.isInfo) { Log.info( $"Sentry error:\n\n{data}\nreporting url={dsn.reportingUrl}\n" + message(loggerName, dsn.keys, appInfo, data, addExtraData) ); } })); }
/// <summary>Tags that will never change during runtime.</summary> public static Dictionary <string, Tag> staticTags(ErrorReporter.AppInfo appInfo) =>
public static SentryMessage message( string loggerName, ApiKeys keys, ErrorReporter.AppInfo appInfo, ErrorReporter.ErrorData data, ExtraData addExtraData ) { var timestamp = DateTime.UtcNow; // The list of frames should be ordered by the oldest call first. // ReSharper disable once ConvertClosureToMethodGroup - MCS bug var stacktraceFrames = data.backtrace.Select(a => backtraceElemToJson(a)).Reverse().ToList(); // Tags are properties that can be filtered/grouped by. var tags = new Dictionary <string, object> { // max tag name length = 32 { "ProductName", tag(appInfo.productName) }, { "BundleIdentifier", tag(appInfo.bundleIdentifier) }, { "App:LoadedLevelNames", tag( Enumerable2.fromImperative(SceneManager.sceneCount, SceneManager.GetSceneAt). Select(_ => $"{_.name}({_.buildIndex})").OrderBy(_ => _).mkString(", ") ) }, { "App:LevelCount", tag(SceneManager.sceneCountInBuildSettings) }, { "App:Platform", tag(Application.platform) }, { "App:UnityVersion", tag(Application.unityVersion) }, { "App:Version", tag(Application.version) }, { "App:BundleIdentifier", tag(Application.bundleIdentifier) }, { "App:InstallMode", tag(Application.installMode) }, { "App:SandboxType", tag(Application.sandboxType) }, { "App:ProductName", tag(Application.productName) }, { "App:CompanyName", tag(Application.companyName) }, { "App:CloudProjectId", tag(Application.cloudProjectId) }, { "App:WebSecurityEnabled", tag(Application.webSecurityEnabled) }, { "App:WebSecurityHostUrl", tag(Application.webSecurityHostUrl) }, { "App:TargetFrameRate", tag(Application.targetFrameRate) }, { "App:SystemLanguage", tag(Application.systemLanguage) }, { "App:BackgroundLoadingPriority", tag(Application.backgroundLoadingPriority) }, { "App:InternetReachability", tag(Application.internetReachability) }, { "App:GenuineCheckAvailable", tag(Application.genuineCheckAvailable) }, { "App:Genuine", tag(Application.genuineCheckAvailable && Application.genuine) }, { "SI:OperatingSystem", tag(SystemInfo.operatingSystem) }, { "SI:ProcessorType", tag(SystemInfo.processorType) }, { "SI:ProcessorCount", tag(SystemInfo.processorCount) }, { "SI:SystemMemorySize", tag(SystemInfo.systemMemorySize) }, { "SI:GraphicsMemorySize", tag(SystemInfo.graphicsMemorySize) }, { "SI:GraphicsDeviceName", tag(SystemInfo.graphicsDeviceName) }, { "SI:GraphicsDeviceVendor", tag(SystemInfo.graphicsDeviceVendor) }, { "SI:GraphicsDeviceID", tag(SystemInfo.graphicsDeviceID) }, { "SI:GraphicsDeviceVendorID", tag(SystemInfo.graphicsDeviceVendorID) }, { "SI:GraphicsDeviceType", tag(SystemInfo.graphicsDeviceType) }, { "SI:GraphicsDeviceVersion", tag(SystemInfo.graphicsDeviceVersion) }, { "SI:GraphicsShaderLevel", tag(SystemInfo.graphicsShaderLevel) }, { "SI:GraphicsMultiThreaded", tag(SystemInfo.graphicsMultiThreaded) }, { "SI:SupportsShadows", tag(SystemInfo.supportsShadows) }, { "SI:SupportsRenderTextures", tag(SystemInfo.supportsRenderTextures) }, { "SI:SupportsRenderToCubemap", tag(SystemInfo.supportsRenderToCubemap) }, { "SI:SupportsImageEffects", tag(SystemInfo.supportsImageEffects) }, { "SI:Supports3DTextures", tag(SystemInfo.supports3DTextures) }, { "SI:SupportsComputeShaders", tag(SystemInfo.supportsComputeShaders) }, { "SI:SupportsInstancing", tag(SystemInfo.supportsInstancing) }, { "SI:SupportsSparseTextures", tag(SystemInfo.supportsSparseTextures) }, { "SI:SupportedRenderTargetCount", tag(SystemInfo.supportedRenderTargetCount) }, { "SI:SupportsStencil", tag(SystemInfo.supportsStencil) }, { "SI:NPOTsupport", tag(SystemInfo.npotSupport) }, { "SI:DeviceName", tag(SystemInfo.deviceName) }, { "SI:DeviceModel", tag(SystemInfo.deviceModel) }, { "SI:SupportsAccelerometer", tag(SystemInfo.supportsAccelerometer) }, { "SI:SupportsGyroscope", tag(SystemInfo.supportsGyroscope) }, { "SI:SupportsLocationService", tag(SystemInfo.supportsLocationService) }, { "SI:SupportsVibration", tag(SystemInfo.supportsVibration) }, { "SI:DeviceType", tag(SystemInfo.deviceType) }, { "SI:MaxTextureSize", tag(SystemInfo.maxTextureSize) }, }; addExtraData.addTags((name, value) => tags[name] = tag(value)); // Extra contextual data is limited to 4096 characters. var extras = new Dictionary <string, object> { { "App:StreamedBytes", Application.streamedBytes }, }; addExtraData.addExtras((name, value) => extras[name] = value); var json = new Dictionary <string, object> { { "event_id", Guid.NewGuid().ToString("N") }, // max length - 1000 chars { "message", data.message.trimTo(1000) }, { "timestamp", timestamp.ToString("yyyy-MM-ddTHH:mm:ss") }, { "level", logTypeToSentryLevel(data.errorType) }, { "logger", loggerName }, { "platform", Application.platform.ToString() }, { "release", appInfo.bundleVersion }, { "tags", tags }, { "extra", extras }, { "stacktrace", new Dictionary <string, object> { { "frames", stacktraceFrames } } } }; if (!data.backtrace.isEmpty()) { json.Add("culprit", data.backtrace[0].method); } var serialized = Formats.MiniJSON.Json.Serialize(json); return(new SentryMessage(keys, timestamp, serialized)); }
public static ErrorReporter.OnError createOnError( string reportingUrl, string apiKey, ErrorReporter.AppInfo appInfo ) { return(data => xml(apiKey, appInfo, data).send(reportingUrl)); }