21#include <rapidjson/document.h>
22#include <rapidjson/writer.h>
23#include <rapidjson/prettywriter.h>
25#include <wx/platinfo.h>
55 std::lock_guard<std::mutex> lock(mDataMutex);
56 mData.emplace_back(std::move(parameterName), std::move(parameterValue));
62 std::lock_guard<std::mutex> lock(mDataMutex);
64 std::vector<ExceptionData> emptyVector;
82 std::vector<ExceptionData>
mData;
87 rapidjson::Value& root, rapidjson::Document::AllocatorType& allocator)
89 rapidjson::Value osContext(rapidjson::kObjectType);
93 const std::string osName =
94 ToUTF8(platformInfo.GetOperatingSystemFamilyName());
96 osContext.AddMember(
"type", rapidjson::Value(
"os", allocator), allocator);
99 "name", rapidjson::Value(osName.c_str(), osName.length(), allocator),
102 const std::string osVersion =
103 std::to_string(platformInfo.GetOSMajorVersion()) +
"." +
104 std::to_string(platformInfo.GetOSMinorVersion()) +
"." +
105 std::to_string(platformInfo.GetOSMicroVersion());
109 rapidjson::Value(osVersion.c_str(), osVersion.length(), allocator),
112 root.AddMember(
"os", std::move(osContext), allocator);
118 using namespace std::chrono;
119 rapidjson::Document document;
121 document.SetObject();
126 duration_cast<seconds>(system_clock::now().time_since_epoch())
128 document.GetAllocator());
135 eventId.c_str(), eventId.length(), document.GetAllocator()),
136 document.GetAllocator());
138 constexpr char platform[] =
"native";
142 rapidjson::Value(platform,
sizeof(platform) - 1, document.GetAllocator()),
143 document.GetAllocator());
145 document[
"platform"].SetString(
146 platform,
sizeof(platform) - 1, document.GetAllocator());
148 const std::string release = std::string(
"audacity@") +
149 std::to_string(AUDACITY_VERSION) +
"." +
150 std::to_string(AUDACITY_RELEASE) +
"." +
151 std::to_string(AUDACITY_REVISION);
156 release.c_str(), release.length(), document.GetAllocator()),
157 document.GetAllocator());
159 rapidjson::Value contexts = rapidjson::Value(rapidjson::kObjectType);
163 document.AddMember(
"contexts", contexts, document.GetAllocator());
170 rapidjson::Value& value, rapidjson::Document::AllocatorType& allocator,
174 rapidjson::Value(data.first.c_str(), data.first.length(), allocator),
175 rapidjson::Value(data.second.c_str(), data.second.length(), allocator),
181 const Exception& exception, rapidjson::Value& root,
182 rapidjson::Document::AllocatorType& allocator)
187 exception.
Type.c_str(), exception.
Type.length(), allocator),
196 rapidjson::Value mechanismObject(rapidjson::kObjectType);
198 mechanismObject.AddMember(
199 "type", rapidjson::Value(
"runtime_error", allocator), allocator);
201 mechanismObject.AddMember(
202 "handled",
false, allocator);
206 if (!exception.
Data.empty() || !contextData.empty())
208 rapidjson::Value dataObject(rapidjson::kObjectType);
210 for (
const auto& data : contextData)
213 for (
const auto& data : exception.
Data)
216 mechanismObject.AddMember(
"data", std::move(dataObject), allocator);
219 root.AddMember(
"mechanism", std::move(mechanismObject), allocator);
226 std::replace_if(type.begin(), type.end(), [](
char c) {
227 return std::isspace(c) != 0;
230 return { std::move(type), std::move(value) };
235 return {
"runtime_error", std::move(value) };
240 Data.emplace_back(std::move(
key), std::move(value));
246 return { std::move(message) };
251 Params.emplace_back(std::move(value));
269 std::string
ToString(
bool pretty)
const;
281 rapidjson::Value exceptionObject(rapidjson::kObjectType);
282 rapidjson::Value valuesArray(rapidjson::kArrayType);
283 rapidjson::Value valueObject(rapidjson::kObjectType);
287 valuesArray.PushBack(std::move(valueObject),
mDocument.GetAllocator());
289 exceptionObject.AddMember(
290 "values", std::move(valuesArray),
mDocument.GetAllocator());
293 "exception", std::move(exceptionObject),
mDocument.GetAllocator());
299 rapidjson::Value messageObject(rapidjson::kObjectType);
301 messageObject.AddMember(
308 if (!message.
Params.empty())
310 rapidjson::Value paramsArray(rapidjson::kArrayType);
314 paramsArray.PushBack(
320 messageObject.AddMember(
321 "params", std::move(paramsArray),
mDocument.GetAllocator());
325 "message", std::move(messageObject),
mDocument.GetAllocator());
331 if (!mDocument.HasMember(
"exception") || message.empty())
334 rapidjson::Value& topException = mDocument[
"exception"][
"values"][0];
336 if (!topException.IsObject())
339 rapidjson::Value& mechanism = topException[
"mechanism"];
342 if (!mechanism.HasMember(
"data"))
345 "data", rapidjson::Value(rapidjson::kObjectType),
346 mDocument.GetAllocator());
350 mechanism[
"data"].AddMember(
353 message.data(), message.length(), mDocument.GetAllocator()),
354 mDocument.GetAllocator());
360 const std::string serializedDocument =
ToString(
false);
366 request, serializedDocument.data(), serializedDocument.size());
368 response->setRequestFinishedCallback(
370 const std::string responseData = response->readAll<std::string>();
372 wxLogDebug(responseData.c_str());
375 handler(response->getHTTPCode(), responseData);
381 rapidjson::StringBuffer buffer;
385 rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
386 mDocument.Accept(writer);
390 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
391 mDocument.Accept(writer);
394 return std::string(buffer.GetString());
413 mImpl->AddUserComment(comment);
418 return mImpl->ToString(
true);
423 mImpl->Send(std::move (completionHandler));
Declare functions to perform UTF-8 to std::wstring conversions.
Declare an interface for HTTP response.
Declare a class for performing HTTP requests.
Declare a class to report errors to Sentry.
Define a class to generate the requests to Sentry.
Declare a class to generate and parse UUIDs.
static Uuid Generate()
Generate a new UUID.
std::string ToHexString() const
Get a string in the xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx format.
Interface, that provides access to the data from the HTTP response.
static NetworkManager & GetInstance()
ResponsePtr doPost(const Request &request, const void *data, size_t size)
A class, that stores anonymized message.
size_t length() const noexcept
Returns the length of the message.
const char * c_str() const noexcept
Checks, if the message is empty.
void Send(CompletionHandler completionHandler) const
rapidjson::Document mDocument
std::string ToString(bool pretty) const
ReportImpl(const Exception &exception)
void AddUserComment(const std::string &message)
void Send(CompletionHandler completionHandler) const
Send the report to Sentry.
std::unique_ptr< ReportImpl > mImpl
std::function< void(int httpCode, std::string responseBody)> CompletionHandler
A callback, that will be called when Send completes.
std::string GetReportPreview() const
Get a pretty printed report preview.
Report(const Exception &exception)
Create a report from the exception and previously added exception context.
void AddUserComment(const std::string &comment)
Adds a user comment to the exception report.
static const SentryRequestBuilder & Get()
network_manager::Request CreateRequest() const
Helper class to store additional details about the exception.
void Add(std::string parameterName, AnonymizedMessage parameterValue)
Adds a new item to the exception context.
ExceptionContext()=default
static ExceptionContext & Get()
Get an instance of the ExceptionContext.
std::vector< ExceptionData > MoveParameters()
Return the current context and reset it.
std::vector< ExceptionData > mData
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
auto ToString(const std::optional< TimeSignature > &ts)
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
AuthorizationHandler handler
void AddExceptionDataToJson(rapidjson::Value &value, rapidjson::Document::AllocatorType &allocator, const ExceptionData &data)
Append the ExceptionData to the Exception JSON object.
rapidjson::Document CreateSentryDocument()
Create the minimal required Sentry JSON document.
void SerializeException(const Exception &exception, rapidjson::Value &root, rapidjson::Document::AllocatorType &allocator)
Serialize the Exception to JSON.
void AddOSContext(rapidjson::Value &root, rapidjson::Document::AllocatorType &allocator)
Append the data about the operating system to the JSON document.
void AddExceptionContext(std::string parameterName, AnonymizedMessage parameterValue)
Saves a parameter, that will be appended to the next Exception report.
std::pair< std::string, AnonymizedMessage > ExceptionData
Additional payload to the exception.
std::string ToUTF8(const std::wstring &wstr)
A DTO for the Sentry Exception interface.
Exception & AddData(std::string key, AnonymizedMessage value)
Add a payload to the exception.
static Exception Create(std::string type, AnonymizedMessage value)
Create a new exception.
AnonymizedMessage Value
Message, associated with the Exception.
std::string Type
Exception type. Should not have spaces.
std::vector< ExceptionData > Data
Arbitrary payload.
A DTO for the Sentry Message interface.
AnonymizedMessage Value
A string, possibly with s placeholders, containing the message.
static Message Create(AnonymizedMessage message)
Create a new Message.
Message & AddParam(AnonymizedMessage value)
Add a parameter to the Message.
std::vector< AnonymizedMessage > Params
Values for the placeholders.