Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Feedback #153

Closed
joshnoe opened this issue Dec 14, 2018 · 14 comments · Fixed by #559
Closed

User Feedback #153

joshnoe opened this issue Dec 14, 2018 · 14 comments · Fixed by #559
Labels
Feature New feature or request

Comments

@joshnoe
Copy link

joshnoe commented Dec 14, 2018

Sentry allows user feedback to be submitted and associated with events.
https://docs.sentry.io/api/projects/post-project-user-reports/

image

It'd be great to have this abstracted into this library. Happy to take it on if it's something that seems appropriate?

@bruno-garcia
Copy link
Member

@joshnoe This is something that would be useful for .NET client apps like WPF and WinForms.
It would be great to get a PR for it too, thanks!

@CADbloke
Copy link

CADbloke commented Jul 15, 2019

+1. It may also be useful to fire a URL at a web browser with the event Id in it if the app is crashing because there will be no UI to host the dialog. A hosted endpoint would be ideal for this, or one we could host ourselves. Oh, I can see the problem here - by the time the event Id gets back the app it may be gone. Leaving this here for ponderings.
To get the last event Id when using things like Serilog etc ... https://github.com/getsentry/sentry-dotnet/blob/master/src/Sentry/SentrySdk.cs#L29 SentrySdk.LastEventId

@bruno-garcia
Copy link
Member

The Id is always defined by the SDK, even before flushing the event to Sentry it'll be available in SentrySdk.LastEventId. That's the case also if the event was sent through the Sentry.Serilog or any other integration.

In a managed desktop app (WinForms, WPF or something), it should be able to display a form to the user before crashing the app. Unless it's crashing due to OutOfMemoryException or some SEHException I assume which either can't be caught or should terminate the app.

The idea of loading a browser at a URL could work. We'd need to support this form somewhere in Sentry.

@CADbloke
Copy link

Thanks for the clarification, I assumed the Id was generated and sent back by the web service. That makes things more straightforward.

@bruno-garcia
Copy link
Member

@CADbloke That happens as a fallback when the client doesn't define the Id. Our SDKs always set the GUID ahead though.

@lucas-zimerman
Copy link
Collaborator

lucas-zimerman commented Nov 16, 2019

I ended up implementing the User Feedback part in our code, it's quite simple but the only issue for now that I see are offline errors and the other point where the CaptureException was called but the user feedback was sent before the error event reached the sentry.io server.
Here's a snip of the code that I'm using

    public class UserFeedback
    {
        [JsonProperty("event_id")]
        public string EventId { get; set; }
        [JsonProperty("name")]
        public string Name { get; set; }
        [JsonProperty("email")]
        public string Email { get; set; }
        [JsonProperty("comments")]
        public string Comments { get; set; }
    }

        public async Task SendSentryUserFeedback(UserFeedback userFeedback)
        {
            var restUrl = SentryFeedbackUrl();
            using (var httpClient = await _httpClientService.GetHttpClient(110, true, TokenSource.SentryToken))
            {
                var content = HttpClientHelper.GetStringContentSerialized(userFeedback);
                var responseMessage = await httpClient.PostAsync(new Uri(restUrl), content);
            }
        }
        public string SentryFeedbackUrl() { return "https://sentry.io/api/0/projects/organization/project/user-feedback/"; }


About UI, it's complicated, because it involves so many platforms, I wouldn't see any problem if the dev would have to implement their layout to the .net platform that they are working with.

@shivan
Copy link

shivan commented Jan 19, 2020

For more clarification, in the url the values seem to be needed to be replaced...

POST /api/0/projects/{organization_slug}/{project_slug}/user-feedback/

see:
https://docs.sentry.io/api/projects/post-project-user-reports/

As your solution did not work, yet for me.

@shivan
Copy link

shivan commented Jan 19, 2020

@ibm5155 where did you trigger your feedback dialog? I currently tried on

sentry = SentrySdk.Init(o =>
    {
     ...
    o.BeforeSend = @event =>
        {
        // open dialog window
        App.SendSentryUserFeedback(feedbackData);
        }
    ...
    }

@lucas-zimerman
Copy link
Collaborator

lucas-zimerman commented Jan 19, 2020

I trigger after an exception, there's a generic function on almost every catch of our code where it sends the sentry exception, get the sent event id and later open the feedback dialog.

But in short , an exception happens, it goes into catch a view is called passing the exception as an argument, I use the feedback screen to Send the error to sentry and to also ask for the feedback, here's a snip of what I do

        private async Task LoadData()
        {
            try
            {
                UiLoading = true;
                sentryEventId = await ExceptionService.SendExceptionAsync(exception, message);
            }
            catch (Exception)
            {
                LogService.RegisterAction($"Get Event Data ({sentryEventId})", "Exception", false, Business.Enums.ELogType.Error);
            }
            finally
            {
                UiLoading = false;
            }
        }

        private Action Report => async () =>
        {
            if (_lockAction) return;
            _lockAction = true;
            UiLoading = true;
            bool success = false;
            try
            {
                LogService.RegisterAction("Report", "ui.click", false, Business.Enums.ELogType.Warning);
                Validate();

                await _sentryReportService.SendSentryUserFeedback(new UserFeedback()
                {
                    Comments = Description,
                    Email = Email,
                    EventId = _eventId,
                    Name = Name
                });
                success = true;
            }

            catch (Exception e)
            {
//...
            }
            finally
            {
                if (success)
                {
                    LogService.RegisterAction("Sent", "console");
                    await NavigateTo("OkPopupPage", new NavigationParameters() {
                        { "OkTitle", "Report Sent!" },
                        { "OkMessage", "Thank you for reporting!"} });
                }
                _lockAction = false;
                UiLoading = false;
            }
        };

@shivan
Copy link

shivan commented Jan 20, 2020

Thanks.

Now I tried with postman to trigger the feedback-url and found, that I need authentication.

		public static void SendSentryUserFeedback(UserFeedback userFeedback)
		{
			var restUrl = SentryFeedbackUrl();

			using (HttpClient httpClient = new HttpClient())
			{
				try
				{
					String json = JsonConvert.SerializeObject(userFeedback);
					HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
					httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("DSN", Dsn);
					
					HttpResponseMessage responseMessage = httpClient.PostAsync(new Uri(restUrl), content).GetAwaiter().GetResult();
					Logger.Info("sent sentry feedback", null);
				} catch (Exception exc)
				{
					MessageBox.Show(exc.Message);
				}
			}
		}

and I did that in the BeforeSend:

				o.BeforeSend = @event =>
				{
					App.LastSentryEventId = @event.EventId.ToString();

					WndWTCrashFeedback feedback = new WndWTCrashFeedback();
					feedback.txtName.Text = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
					if (feedback.ShowDialog() == true)
					{
						UserFeedback feedbackData = feedback.getFeedbackData();
						feedbackData.EventId = @event.EventId.ToString();
						App.SendSentryUserFeedback(feedbackData);
					}

					return @event;
				};

That really worked for me now. I think your example @ibm5155 was using ASP. I'm using WPF.

@bruno-garcia
Copy link
Member

Sentry needs an endpoint that can take a UserFeedback request built with the information contained in a DSN. Meaning without org and project slugs. I don't think it's planned right now but it's in the backlog.

@bruno-garcia
Copy link
Member

bruno-garcia commented Oct 20, 2020

Some update: We're adding this to Sentry Cocoa: getsentry/sentry-cocoa#805, requested here.

Sentry Java also got this request, 4 years ago.

And given that this SDK now got Envelopes (#544) it should be straight forward to add it here. So coming soon :)

@lucas-zimerman
Copy link
Collaborator

that's great news @bruno-garcia :D

@bruno-garcia
Copy link
Member

Thanks for adding this @lucas-zimerman !
I'll push another alpha later today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants