예제 #1
0
        public string SaveCrashReport(RaygunMessage crashReport, int maxReportsStored)
        {
            try
            {
                // Can only save the report if we havnt reached the report count limit.
                if (IsFileLimitReached(Math.Min(maxReportsStored, MAX_STORED_REPORTS_UPPER_LIMIT)))
                {
                    RaygunLogger.Warning("Failed to store crash report - Reached max crash reports stored on device");
                    return(null);
                }

                // Convert to JSON text.
                var reportJson = SimpleJson.SerializeObject(crashReport);

                // Generate a unique name for our report.
                var fileName = GetUniqueAcendingJsonName();

                // Save the report to disk.
                return(StoreCrashReport(fileName, reportJson));
            }
            catch (Exception ex)
            {
                RaygunLogger.Error(string.Format("Failed to store crash report - Error saving message to isolated storage {0}", ex.Message));
            }

            return(null);
        }
예제 #2
0
        public void RemoveFile(string filePath)
        {
            // Validate the file path.
            if (string.IsNullOrEmpty(filePath))
            {
                RaygunLogger.Debug("Failed to remove file - Invalid file path");
                return;
            }

            // Check a file exists at this path.
            if (!File.Exists(filePath))
            {
                RaygunLogger.Debug("Failed to remove file - File does not exist");
                return;
            }

            try
            {
                File.Delete(filePath);
            }
            catch (Exception e)
            {
                RaygunLogger.Error("Failed to remove file - Due to error: " + e.Message);
            }
        }
예제 #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RaygunClient" /> class.
        /// </summary>
        /// <param name="apiKey">The API key.</param>
        public RaygunClient(string apiKey)
        {
            _apiKey = apiKey;

            _fileManager = new RaygunFileManager();
            _fileManager.Intialise();

            MaxReportsStoredOnDevice = RaygunFileManager.MAX_STORED_REPORTS_UPPER_LIMIT;

            // Setting default user information.
            var anonUser = GetAnonymousUserInfo();

            _userInfo = anonUser;
            _user     = anonUser.Identifier;

            _wrapperExceptions.Add(typeof(TargetInvocationException));
            _wrapperExceptions.Add(typeof(AggregateException));

            try
            {
                var clientVersion = new AssemblyName(GetType().Assembly.FullName).Version.ToString();
                RaygunLogger.Info(string.Format("Configuring Raygun ({0})", clientVersion));
            }
            catch
            {
                // Ignore
            }
        }
예제 #4
0
        internal int SendMessage(string message)
        {
            RaygunLogger.Verbose("Sending JSON -------------------------------");
            RaygunLogger.Verbose(message);
            RaygunLogger.Verbose("--------------------------------------------");

            using (var client = new WebClient())
            {
                client.Headers.Add("X-ApiKey", _apiKey);
                client.Headers.Add("content-type", "application/json; charset=utf-8");
                client.Encoding = System.Text.Encoding.UTF8;

                try
                {
                    client.UploadString(RaygunSettings.Settings.ApiEndpoint, message);
                }
                catch (Exception e)
                {
                    RaygunLogger.Error(string.Format("Error Logging Exception to Raygun.io {0}", e.Message));

                    if (e.GetType().Name == "WebException")
                    {
                        WebException    we       = (WebException)e;
                        HttpWebResponse response = (HttpWebResponse)we.Response;

                        return((int)response.StatusCode);
                    }
                }
            }

            return((int)HttpStatusCode.Accepted);
        }
예제 #5
0
        private async Task SendStoredReportAsync(HttpClient client, RaygunFile report)
        {
            try
            {
                RaygunLogger.Verbose("Sending JSON -------------------------------");
                RaygunLogger.Verbose(report.Data);
                RaygunLogger.Verbose("--------------------------------------------");

                // Create the request contnet.
                HttpContent content = new StringContent(report.Data, System.Text.Encoding.UTF8, "application/json");

                // Add API key to headers.
                content.Headers.Add("X-ApiKey", _apiKey);

                // Perform the request.
                var response = await client.PostAsync(RaygunSettings.Settings.ApiEndpoint, content);

                // Check the response.
                var statusCode = (int)response.StatusCode;

                RaygunLogger.LogResponseStatusCode(statusCode);

                // Remove the stored crash report if it was sent successfully.
                if (statusCode == (int)RaygunResponseStatusCode.Accepted)
                {
                    _fileManager.RemoveFile(report.Path); // We can delete the file from disk now.
                }
            }
            catch (Exception e)
            {
                RaygunLogger.Error("Failed to send stored crash report due to error: " + e.Message);
            }
        }
예제 #6
0
        /// <summary>
        /// Sends a pulse timing event to Raygun. The message is sent on a background thread.
        /// </summary>
        /// <param name="eventType">The type of event that occurred.</param>
        /// <param name="name">The name of the event resource such as the activity name or URL of a network call.</param>
        /// <param name="milliseconds">The duration of the event in milliseconds.</param>
        public void SendPulseTimingEvent(RaygunPulseEventType eventType, string name, long milliseconds)
        {
            lock (_batchLock)
            {
                try
                {
                    if (_activeBatch == null)
                    {
                        _activeBatch = new PulseEventBatch(this);
                    }

                    if (_activeBatch != null && !_activeBatch.IsLocked)
                    {
                        EnsurePulseSessionStarted();

                        PendingEvent pendingEvent = new PendingEvent(eventType, name, milliseconds, _sessionId);
                        _activeBatch.Add(pendingEvent);
                    }
                    else
                    {
                        ThreadPool.QueueUserWorkItem(c => SendPulseTimingEventCore(eventType, name, milliseconds));
                    }
                }
                catch (Exception e)
                {
                    RaygunLogger.Error(string.Format("Error sending pulse timing event to Raygun: {0}", e.Message));
                }
            }
        }
예제 #7
0
        private string GetVersion()
        {
            string version = ApplicationVersion;

            if (String.IsNullOrWhiteSpace(version))
            {
                try
                {
                    Context        context = RaygunClient.Context;
                    PackageManager manager = context.PackageManager;
                    PackageInfo    info    = manager.GetPackageInfo(context.PackageName, 0);
                    version = info.VersionCode + " / " + info.VersionName;
                }
                catch (Exception ex)
                {
                    RaygunLogger.Warning(string.Format("Error retrieving package version {0}", ex.Message));
                }
            }

            if (String.IsNullOrWhiteSpace(version))
            {
                version = "Not supplied";
            }

            return(version);
        }
예제 #8
0
        private void SendAllStoredCrashReports()
        {
            if (!HasInternetConnection)
            {
                RaygunLogger.Debug("Not sending stored crash reports due to no internet connection");
                return;
            }

            // Get all stored crash reports.
            var reports = _fileManager.GetAllStoredCrashReports();

            RaygunLogger.Debug(string.Format("Attempting to send {0} stored crash report(s)", reports.Count));

            // Quick escape if there's no crash reports.
            if (reports.Count == 0)
            {
                return;
            }

            // Run on another thread.
            Task.Run(async() => {
                // Use a single HttpClient for all requests.
                using (var client = new HttpClient())
                {
                    foreach (var report in reports)
                    {
                        try
                        {
                            RaygunLogger.Verbose("Sending JSON -------------------------------");
                            RaygunLogger.Verbose(report.Data);
                            RaygunLogger.Verbose("--------------------------------------------");

                            // Create the request contnet.
                            HttpContent content = new StringContent(report.Data, System.Text.Encoding.UTF8, "application/json");

                            // Add API key to headers.
                            content.Headers.Add("X-ApiKey", _apiKey);

                            // Perform the request.
                            var response = await client.PostAsync(RaygunSettings.Settings.ApiEndpoint, content);

                            // Check the response.
                            var statusCode = (int)response.StatusCode;

                            RaygunLogger.LogResponseStatusCode(statusCode);

                            // Remove the stored crash report if it was sent successfully.
                            if (statusCode == (int)RaygunResponseStatusCode.Accepted)
                            {
                                _fileManager.RemoveFile(report.Path); // We can delete the file from disk now.
                            }
                        }
                        catch (Exception e)
                        {
                            RaygunLogger.Error("Failed to send stored crash report due to error: " + e.Message);
                        }
                    }
                }
            });
        }
예제 #9
0
        public List <RaygunFile> GetAllStoredCrashReports()
        {
            var allReports = new List <RaygunFile>();

            try
            {
                // Get the paths to all the files in the crash report directory.
                var files = Directory.GetFiles(GetCrashReportDirectory());

                foreach (var file in files)
                {
                    // Generate the full file path.
                    var filePath = Path.Combine(GetCrashReportDirectory(), file);

                    // Read the content of the file on disk.
                    var raygunFile = ReadCrashReportFromDisk(filePath);

                    // Add it to our list if valid.
                    if (raygunFile != null && raygunFile.Data != null)
                    {
                        allReports.Add(raygunFile);
                    }
                }
            }
            catch (Exception ex)
            {
                RaygunLogger.Error(string.Format("Error sending stored messages to Raygun.io {0}", ex.Message));
            }

            return(allReports);
        }
예제 #10
0
        public IRaygunMessageBuilder SetVersion(string version)
        {
            if (String.IsNullOrWhiteSpace(version))
            {
                try
                {
                    Context        context = RaygunClient.Context;
                    PackageManager manager = context.PackageManager;
                    PackageInfo    info    = manager.GetPackageInfo(context.PackageName, 0);
                    version = info.VersionCode + " / " + info.VersionName;
                }
                catch (Exception ex)
                {
                    RaygunLogger.Debug(string.Format("Error retrieving package version {0}", ex.Message));
                }
            }

            if (String.IsNullOrWhiteSpace(version))
            {
                version = "Not supplied";
            }

            _raygunMessage.Details.Version = version;

            return(this);
        }
예제 #11
0
        /// <summary>
        /// Causes Raygun to automatically send session and view events for Raygun Pulse.
        /// </summary>
        /// <param name="mainActivity">The main/entry activity of the Android app.</param>
        /// <returns>The RaygunClient to chain other methods.</returns>
        public RaygunClient AttachPulse(Activity mainActivity)
        {
            RaygunLogger.Debug("Enabling Real User Monitoring");

            Pulse.Attach(this, mainActivity);

            return(this);
        }
예제 #12
0
 private bool ValidateApiKey()
 {
     if (string.IsNullOrEmpty(_apiKey))
     {
         RaygunLogger.Error("ApiKey has not been provided, exception will not be logged");
         return(false);
     }
     return(true);
 }
예제 #13
0
        private void SendCore(PulseEventBatch batch)
        {
            try
            {
                EnsurePulseSessionStarted();

                string version   = GetVersion();
                string os        = "Android";
                string osVersion = Android.OS.Build.VERSION.Release;
                string platform  = string.Format("{0} {1}", Android.OS.Build.Manufacturer, Android.OS.Build.Model);

                RaygunPulseMessage message = new RaygunPulseMessage();

                RaygunLogger.Debug("BatchSize: " + batch.PendingEventCount);

                RaygunPulseDataMessage[] eventMessages = new RaygunPulseDataMessage[batch.PendingEventCount];
                int index = 0;

                foreach (PendingEvent pendingEvent in batch.PendingEvents)
                {
                    RaygunPulseDataMessage dataMessage = new RaygunPulseDataMessage();
                    dataMessage.SessionId = pendingEvent.SessionId;
                    dataMessage.Timestamp = pendingEvent.Timestamp;
                    dataMessage.Version   = version;
                    dataMessage.OS        = os;
                    dataMessage.OSVersion = osVersion;
                    dataMessage.Platform  = platform;
                    dataMessage.Type      = "mobile_event_timing";
                    dataMessage.User      = batch.UserInfo;

                    string type = pendingEvent.EventType == RaygunPulseEventType.ViewLoaded ? "p" : "n";

                    RaygunPulseData data = new RaygunPulseData()
                    {
                        Name = pendingEvent.Name, Timing = new RaygunPulseTimingMessage()
                        {
                            Type = type, Duration = pendingEvent.Duration
                        }
                    };

                    RaygunPulseData[] dataArray = { data };
                    string            dataStr   = SimpleJson.SerializeObject(dataArray);
                    dataMessage.Data = dataStr;

                    eventMessages[index] = dataMessage;
                    index++;
                }
                message.EventData = eventMessages;

                Send(message);
            }
            catch (Exception e)
            {
                RaygunLogger.Error(string.Format("Error sending pulse event batch to Raygun: {0}", e.Message));
            }
        }
예제 #14
0
        /// <summary>
        /// Causes Raygun to listen to and send all unhandled exceptions and unobserved task exceptions.
        /// </summary>
        /// <returns>The RaygunClient to chain other methods.</returns>
        public RaygunClient AttachCrashReporting()
        {
            RaygunLogger.Debug("Enabling Crash Reporting");

            RaygunClient.DetachCrashReporting();

            SetUnhandledExceptionHandlers();

            return(this);
        }
예제 #15
0
 private static void SetUnhandledExceptionHandlers()
 {
     if (!_exceptionHandlersSet)
     {
         _exceptionHandlersSet = true;
         RaygunLogger.Debug("Adding exception handlers");
         AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
         TaskScheduler.UnobservedTaskException      += TaskScheduler_UnobservedTaskException;
     }
 }
예제 #16
0
 private static void RemoveUnhandledExceptionHandlers()
 {
     if (_exceptionHandlersSet)
     {
         _exceptionHandlersSet = false;
         RaygunLogger.Debug("Removing exception handlers");
         AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
         TaskScheduler.UnobservedTaskException      -= TaskScheduler_UnobservedTaskException;
     }
 }
예제 #17
0
        internal int SendMessage(string message, int timeout)
        {
            RaygunLogger.Verbose("Sending JSON -------------------------------");
            RaygunLogger.Verbose(message);
            RaygunLogger.Verbose("--------------------------------------------");

            int statusCode = 0;

            using (var client = new HttpClient())
            {
                try
                {
                    // Set the timeout
                    if (timeout > 0)
                    {
                        client.Timeout = TimeSpan.FromMilliseconds(timeout);
                    }

                    // Create the request contnet.
                    HttpContent content = new StringContent(message, System.Text.Encoding.UTF8, "application/json");

                    // Add API key to headers.
                    content.Headers.Add("X-ApiKey", _apiKey);

                    // Perform the request.
                    var task = client.PostAsync(RaygunSettings.Settings.ApiEndpoint, content);

                    task.Wait();

                    var response = task.Result;

                    // Check the response.
                    statusCode = (int)response.StatusCode;
                }
                catch (Exception e)
                {
                    RaygunLogger.Error(string.Format("Failed to send message due to error {0}: {1}", e.GetType().Name, e.Message));

                    // Was this due to the request timing out?
                    const string TaskCanceledEx = "TaskCanceledException";
                    if (e.GetType().Name == TaskCanceledEx || e.InnerException.GetType().Name == TaskCanceledEx)
                    {
                        statusCode = (int)HttpStatusCode.RequestTimeout;
                    }
                    else
                    {
                        statusCode = (int)HttpStatusCode.BadRequest;
                    }
                }
            }

            return(statusCode);
        }
예제 #18
0
 /// <summary>
 /// Asynchronously transmits a message to Raygun.io.
 /// </summary>
 /// <param name="exception">The exception to deliver.</param>
 /// <param name="tags">A list of strings associated with the message.</param>
 /// <param name="userCustomData">A key-value collection of custom data that will be added to the payload.</param>
 public void SendInBackground(Exception exception, IList <string> tags, IDictionary userCustomData)
 {
     if (CanSend(exception))
     {
         ThreadPool.QueueUserWorkItem(c => StripAndSend(exception, tags, userCustomData, 0));
         FlagAsSent(exception);
     }
     else
     {
         RaygunLogger.Debug("Not sending exception in background");
     }
 }
예제 #19
0
 /// <summary>
 /// Transmits an exception to Raygun.io synchronously specifying a list of string tags associated
 /// with the message for identification, as well as sending a key-value collection of custom data.
 /// This uses the version number of the originating assembly.
 /// </summary>
 /// <param name="exception">The exception to deliver.</param>
 /// <param name="tags">A list of strings associated with the message.</param>
 /// <param name="userCustomData">A key-value collection of custom data that will be added to the payload.</param>
 public void Send(Exception exception, IList <string> tags, IDictionary userCustomData)
 {
     if (CanSend(exception))
     {
         StripAndSend(exception, tags, userCustomData, SynchronousTimeout);
         FlagAsSent(exception);
     }
     else
     {
         RaygunLogger.Debug("Not sending exception");
     }
 }
예제 #20
0
        public void Intialise()
        {
            try
            {
                var crashReportDirectory = GetCrashReportDirectory();

                if (!Directory.Exists(crashReportDirectory))
                {
                    Directory.CreateDirectory(crashReportDirectory);
                }
            }
            catch (Exception e)
            {
                RaygunLogger.Error("Failed to initialise file manager due to error: " + e.Message);
            }
        }
예제 #21
0
 protected void FlagAsSent(Exception exception)
 {
     if (exception != null && exception.Data != null)
     {
         try
         {
             Type[] genericTypes = exception.Data.GetType().GetGenericArguments();
             if (genericTypes.Length == 0 || genericTypes[0].IsAssignableFrom(typeof(string)))
             {
                 exception.Data[SentKey] = true;
             }
         }
         catch (Exception ex)
         {
             RaygunLogger.Debug($"Failed to flag exception as sent: {ex.Message}");
         }
     }
 }
예제 #22
0
        private void Send(RaygunPulseMessage raygunPulseMessage)
        {
            if (ValidateApiKey())
            {
                string message = null;
                try
                {
                    message = SimpleJson.SerializeObject(raygunPulseMessage);
                }
                catch (Exception ex)
                {
                    RaygunLogger.Error(string.Format("Error serializing message {0}", ex.Message));
                }

                if (message != null)
                {
                    SendPulseMessage(message);
                }
            }
        }
예제 #23
0
        private bool SendPulseMessage(string message)
        {
            using (var client = new WebClient())
            {
                client.Headers.Add("X-ApiKey", _apiKey);
                client.Headers.Add("content-type", "application/json; charset=utf-8");
                client.Encoding = System.Text.Encoding.UTF8;

                try
                {
                    client.UploadString(RaygunSettings.Settings.PulseEndpoint, message);
                }
                catch (Exception ex)
                {
                    RaygunLogger.Error(string.Format("Error Logging Pulse message to Raygun.io {0}", ex.Message));
                    return(false);
                }
            }
            return(true);
        }
예제 #24
0
        private void Send(RaygunMessage raygunMessage, int timeout)
        {
            if (!ValidateApiKey())
            {
                RaygunLogger.Error("Failed to send due to invalid API key");
                return;
            }

            bool canSend = OnSendingMessage(raygunMessage);

            if (!canSend)
            {
                RaygunLogger.Debug("Sending message cancelled");
                return;
            }

            // No internet then we store the report.
            if (!HasInternetConnection)
            {
                var path = _fileManager.SaveCrashReport(raygunMessage, MaxReportsStoredOnDevice);

                if (!string.IsNullOrEmpty(path))
                {
                    RaygunLogger.Debug("Saved crash report to: " + path);
                }

                return;
            }

            try
            {
                // Create the json data.
                var jsonData = SimpleJson.SerializeObject(raygunMessage);

                var statusCode = SendMessage(jsonData, timeout);

                RaygunLogger.LogResponseStatusCode(statusCode);

                // Save the message if the application is currently being rate limited or there was a timeout.
                if (statusCode == (int)RaygunResponseStatusCode.RateLimited ||
                    statusCode == (int)RaygunResponseStatusCode.RequestTimeout ||
                    statusCode == (int)RaygunResponseStatusCode.GatewayTimeout)
                {
                    var path = _fileManager.SaveCrashReport(raygunMessage, MaxReportsStoredOnDevice);

                    if (!string.IsNullOrEmpty(path))
                    {
                        RaygunLogger.Debug("Saved crash report to: " + path);
                    }
                }
            }
            catch (Exception e)
            {
                RaygunLogger.Error(string.Format("Failed to send message due to error {0}: {1}", e.GetType().Name, e.Message));

                var path = _fileManager.SaveCrashReport(raygunMessage, MaxReportsStoredOnDevice);

                if (!string.IsNullOrEmpty(path))
                {
                    RaygunLogger.Debug("Saved crash report to: " + path);
                }
            }
        }
예제 #25
0
        private void SendAllStoredCrashReports()
        {
            if (!HasInternetConnection)
            {
                RaygunLogger.Debug("Not sending stored crash reports due to no internet connection");
                return;
            }

            // Get all stored crash reports.
            var reports = _fileManager.GetAllStoredCrashReports();

            RaygunLogger.Info(string.Format("Attempting to send {0} stored crash report(s)", reports.Count));

            // Quick escape if there's no crash reports.
            if (reports.Count == 0)
            {
                return;
            }

            try
            {
                Task.Run(async() =>
                {
                    // Use a single HttpClient for all requests.
                    using (var client = new HttpClient())
                    {
                        foreach (var report in reports)
                        {
                            await SendStoredReportAsync(client, report);
                        }
                    }
                }).ContinueWith(t =>
                {
                    if (t != null && t.IsFaulted)
                    {
                        RaygunLogger.Error("Fault occurred when sending stored reports - clearing stored reports");

                        try
                        {
                            // If there was an issue then clear the stored reports.
                            _fileManager.RemoveFiles(reports);
                        }
                        catch (Exception e)
                        {
                            RaygunLogger.Error("Failed to remove stored report due to error: " + e.Message);
                        }
                    }

                    if (t != null && t.Exception != null)
                    {
                        // Consume all errors as we dont want them being sent.
                        t.Exception.Handle((e) =>
                        {
                            RaygunLogger.Error("Error occurred while sending stored reports: " + e.Message);
                            return(true); // Handled
                        });
                    }
                });
            }
            catch (Exception e)
            {
                RaygunLogger.Error("Failed to send stored reports due to error: " + e.Message);
            }
        }