mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
handler: Add --monitor-self-annotations
--monitor-self-annotations allows the Crashpad-using application to push module-level annotations in to crashpad_handler. These annotations will appear in any crash report written for that handler by --monitor-self. Bug: crashpad:143 Change-Id: If47395da75a90be4f4bdce0630ce95ea93f9fcf3 Reviewed-on: https://chromium-review.googlesource.com/467746 Reviewed-by: Scott Graham <scottmg@chromium.org>
This commit is contained in:
parent
45305395ad
commit
8f07f7481a
@ -149,15 +149,28 @@ establish the Crashpad client environment before running a program.
|
|||||||
Causes a second instance of the Crashpad handler program to be started,
|
Causes a second instance of the Crashpad handler program to be started,
|
||||||
monitoring the original instance for exceptions. The original instance will
|
monitoring the original instance for exceptions. The original instance will
|
||||||
become a client of the second one. The second instance will be started with
|
become a client of the second one. The second instance will be started with
|
||||||
the same **--annotation**, **--database**, **--no-rate-limit**,
|
the same **--annotation**, **--database**, **--monitor-self-annotation**,
|
||||||
**--no-upload-gzip**, and **--url** arguments as the original one. The second
|
**--no-rate-limit**, **--no-upload-gzip**, and **--url** arguments as the
|
||||||
instance will not be started with a **--metrics-dir** argument even if the
|
original one. The second instance will not be started with a
|
||||||
original instance was.
|
**--metrics-dir** argument even if the original instance was.
|
||||||
|
|
||||||
Where supported by the underlying operating system, the second instance will
|
Where supported by the underlying operating system, the second instance will
|
||||||
be restarted should it exit before the first instance. The second instance
|
be restarted should it exit before the first instance. The second instance
|
||||||
will not be eligible to be started asynchronously.
|
will not be eligible to be started asynchronously.
|
||||||
|
|
||||||
|
* **--monitor-self-annotation**=_KEY_=_VALUE_
|
||||||
|
|
||||||
|
Sets a module-level annotation mapping _KEY_ to _VALUE_ in the Crashpad
|
||||||
|
handler. This option may appear zero, one, or more times.
|
||||||
|
|
||||||
|
If **--monitor-self** is in use, the second instance of the Crashpad handler
|
||||||
|
program will find these annotations stored in the original instance and will
|
||||||
|
include them in any crash reports written for the original instance.
|
||||||
|
|
||||||
|
These annotations will only appear in crash reports written for the Crashpad
|
||||||
|
handler itself. To apply a process-level annotation to all crash reports
|
||||||
|
written by an instance of the Crashpad handler, use **--annotation** instead.
|
||||||
|
|
||||||
* **--monitor-self-argument**=_ARGUMENT_
|
* **--monitor-self-argument**=_ARGUMENT_
|
||||||
|
|
||||||
When directed by **--monitor-self** to start a second instance of the
|
When directed by **--monitor-self** to start a second instance of the
|
||||||
|
@ -34,11 +34,14 @@
|
|||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "base/metrics/persistent_histogram_allocator.h"
|
#include "base/metrics/persistent_histogram_allocator.h"
|
||||||
#include "base/scoped_generic.h"
|
#include "base/scoped_generic.h"
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
#include "client/crash_report_database.h"
|
#include "client/crash_report_database.h"
|
||||||
#include "client/crashpad_client.h"
|
#include "client/crashpad_client.h"
|
||||||
|
#include "client/crashpad_info.h"
|
||||||
#include "client/prune_crash_reports.h"
|
#include "client/prune_crash_reports.h"
|
||||||
|
#include "client/simple_string_dictionary.h"
|
||||||
#include "handler/crash_report_upload_thread.h"
|
#include "handler/crash_report_upload_thread.h"
|
||||||
#include "handler/prune_crash_reports_thread.h"
|
#include "handler/prune_crash_reports_thread.h"
|
||||||
#include "tools/tool_support.h"
|
#include "tools/tool_support.h"
|
||||||
@ -102,6 +105,8 @@ void Usage(const base::FilePath& me) {
|
|||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
" --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n"
|
" --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n"
|
||||||
" --monitor-self run a second handler to catch crashes in the first\n"
|
" --monitor-self run a second handler to catch crashes in the first\n"
|
||||||
|
" --monitor-self-annotation=KEY=VALUE\n"
|
||||||
|
" set a module annotation in the handler\n"
|
||||||
" --monitor-self-argument=ARGUMENT\n"
|
" --monitor-self-argument=ARGUMENT\n"
|
||||||
" provide additional arguments to the second handler\n"
|
" provide additional arguments to the second handler\n"
|
||||||
" --no-rate-limit don't rate limit crash uploads\n"
|
" --no-rate-limit don't rate limit crash uploads\n"
|
||||||
@ -123,6 +128,7 @@ void Usage(const base::FilePath& me) {
|
|||||||
|
|
||||||
struct Options {
|
struct Options {
|
||||||
std::map<std::string, std::string> annotations;
|
std::map<std::string, std::string> annotations;
|
||||||
|
std::map<std::string, std::string> monitor_self_annotations;
|
||||||
std::string url;
|
std::string url;
|
||||||
base::FilePath database;
|
base::FilePath database;
|
||||||
base::FilePath metrics_dir;
|
base::FilePath metrics_dir;
|
||||||
@ -140,6 +146,29 @@ struct Options {
|
|||||||
bool upload_gzip;
|
bool upload_gzip;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Splits |key_value| on '=' and inserts the resulting key and value into |map|.
|
||||||
|
// If |key_value| has the wrong format, logs an error and returns false. If the
|
||||||
|
// key is already in the map, logs a warning, replaces the existing value, and
|
||||||
|
// returns true. If the key and value were inserted into the map, returns true.
|
||||||
|
// |argument| is used to give context to logged messages.
|
||||||
|
bool AddKeyValueToMap(std::map<std::string, std::string>* map,
|
||||||
|
const std::string& key_value,
|
||||||
|
const char* argument) {
|
||||||
|
std::string key;
|
||||||
|
std::string value;
|
||||||
|
if (!SplitStringFirst(key_value, '=', &key, &value)) {
|
||||||
|
LOG(ERROR) << argument << " requires KEY=VALUE";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string old_value;
|
||||||
|
if (!MapInsertOrReplace(map, key, value, &old_value)) {
|
||||||
|
LOG(WARNING) << argument << " has duplicate key " << key
|
||||||
|
<< ", discarding value " << old_value;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Calls Metrics::HandlerLifetimeMilestone, but only on the first call. This is
|
// Calls Metrics::HandlerLifetimeMilestone, but only on the first call. This is
|
||||||
// to prevent multiple exit events from inadvertently being recorded, which
|
// to prevent multiple exit events from inadvertently being recorded, which
|
||||||
// might happen if a crash occurs during destruction in what would otherwise be
|
// might happen if a crash occurs during destruction in what would otherwise be
|
||||||
@ -292,7 +321,7 @@ class TerminateHandler final : public SessionEndWatcher {
|
|||||||
void ReinstallCrashHandler() {
|
void ReinstallCrashHandler() {
|
||||||
// This is used to re-enable the metrics-recording crash handler after
|
// This is used to re-enable the metrics-recording crash handler after
|
||||||
// MonitorSelf() sets up a Crashpad exception handler. The Crashpad handler
|
// MonitorSelf() sets up a Crashpad exception handler. The Crashpad handler
|
||||||
// takes over the UnhandledExceptionFilter, so reintsall the metrics-recording
|
// takes over the UnhandledExceptionFilter, so reinstall the metrics-recording
|
||||||
// one.
|
// one.
|
||||||
g_original_exception_filter =
|
g_original_exception_filter =
|
||||||
SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
|
SetUnhandledExceptionFilter(&UnhandledExceptionHandler);
|
||||||
@ -330,6 +359,12 @@ void MonitorSelf(const Options& options) {
|
|||||||
if (!options.upload_gzip) {
|
if (!options.upload_gzip) {
|
||||||
extra_arguments.push_back("--no-upload-gzip");
|
extra_arguments.push_back("--no-upload-gzip");
|
||||||
}
|
}
|
||||||
|
for (const auto& iterator : options.monitor_self_annotations) {
|
||||||
|
extra_arguments.push_back(
|
||||||
|
base::StringPrintf("--monitor-self-annotation=%s=%s",
|
||||||
|
iterator.first.c_str(),
|
||||||
|
iterator.second.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
// Don’t use options.metrics_dir. The current implementation only allows one
|
// Don’t use options.metrics_dir. The current implementation only allows one
|
||||||
// instance of crashpad_handler to be writing metrics at a time, and it should
|
// instance of crashpad_handler to be writing metrics at a time, and it should
|
||||||
@ -377,6 +412,7 @@ int HandlerMain(int argc, char* argv[]) {
|
|||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
kOptionMetrics,
|
kOptionMetrics,
|
||||||
kOptionMonitorSelf,
|
kOptionMonitorSelf,
|
||||||
|
kOptionMonitorSelfAnnotation,
|
||||||
kOptionMonitorSelfArgument,
|
kOptionMonitorSelfArgument,
|
||||||
kOptionNoRateLimit,
|
kOptionNoRateLimit,
|
||||||
kOptionNoUploadGzip,
|
kOptionNoUploadGzip,
|
||||||
@ -410,6 +446,10 @@ int HandlerMain(int argc, char* argv[]) {
|
|||||||
#endif // OS_MACOSX
|
#endif // OS_MACOSX
|
||||||
{"metrics-dir", required_argument, nullptr, kOptionMetrics},
|
{"metrics-dir", required_argument, nullptr, kOptionMetrics},
|
||||||
{"monitor-self", no_argument, nullptr, kOptionMonitorSelf},
|
{"monitor-self", no_argument, nullptr, kOptionMonitorSelf},
|
||||||
|
{"monitor-self-annotation",
|
||||||
|
required_argument,
|
||||||
|
nullptr,
|
||||||
|
kOptionMonitorSelfAnnotation},
|
||||||
{"monitor-self-argument",
|
{"monitor-self-argument",
|
||||||
required_argument,
|
required_argument,
|
||||||
nullptr,
|
nullptr,
|
||||||
@ -442,17 +482,9 @@ int HandlerMain(int argc, char* argv[]) {
|
|||||||
while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
|
while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case kOptionAnnotation: {
|
case kOptionAnnotation: {
|
||||||
std::string key;
|
if (!AddKeyValueToMap(&options.annotations, optarg, "--annotation")) {
|
||||||
std::string value;
|
|
||||||
if (!SplitStringFirst(optarg, '=', &key, &value)) {
|
|
||||||
ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE");
|
|
||||||
return ExitFailure();
|
return ExitFailure();
|
||||||
}
|
}
|
||||||
std::string old_value;
|
|
||||||
if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) {
|
|
||||||
LOG(WARNING) << "duplicate key " << key << ", discarding value "
|
|
||||||
<< old_value;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kOptionDatabase: {
|
case kOptionDatabase: {
|
||||||
@ -494,6 +526,14 @@ int HandlerMain(int argc, char* argv[]) {
|
|||||||
options.monitor_self = true;
|
options.monitor_self = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case kOptionMonitorSelfAnnotation: {
|
||||||
|
if (!AddKeyValueToMap(&options.monitor_self_annotations,
|
||||||
|
optarg,
|
||||||
|
"--monitor-self-annotation")) {
|
||||||
|
return ExitFailure();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case kOptionMonitorSelfArgument: {
|
case kOptionMonitorSelfArgument: {
|
||||||
options.monitor_self_arguments.push_back(optarg);
|
options.monitor_self_arguments.push_back(optarg);
|
||||||
break;
|
break;
|
||||||
@ -584,6 +624,17 @@ int HandlerMain(int argc, char* argv[]) {
|
|||||||
MonitorSelf(options);
|
MonitorSelf(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!options.monitor_self_annotations.empty()) {
|
||||||
|
// Establish these annotations even if --monitor-self is not present, in
|
||||||
|
// case something such as generate_dump wants to try to access them later.
|
||||||
|
SimpleStringDictionary* module_annotations = new SimpleStringDictionary();
|
||||||
|
for (const auto& iterator : options.monitor_self_annotations) {
|
||||||
|
module_annotations->SetKeyValue(iterator.first.c_str(),
|
||||||
|
iterator.second.c_str());
|
||||||
|
}
|
||||||
|
CrashpadInfo::GetCrashpadInfo()->set_simple_annotations(module_annotations);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(OS_MACOSX)
|
#if defined(OS_MACOSX)
|
||||||
if (options.mach_service.empty()) {
|
if (options.mach_service.empty()) {
|
||||||
// Don’t do this when being run by launchd. See launchd.plist(5).
|
// Don’t do this when being run by launchd. See launchd.plist(5).
|
||||||
|
Loading…
x
Reference in New Issue
Block a user