processor: Expose a C++ API for ExportJson to chrome

Turns out this makes a few things simpler for chrome:
(1) Chrome uses argument/metadata/label filters, which are predicates.
(2) Makes it possible to pass in something other than an FD for output.

(1) is tricky to solve declaratively given the complexity of these
filters and the existing legacy code in chromium. (2) could be solved
by providing a memory-backed FILE* on posix (fmemopen) - but not so
easily on windows.

Thus this new API allows providing the filter predicates (impl TODO)
and a custom writer for output.

Bug: 130786269
Change-Id: I002e67d5160157bd494c85dbe2c159695bd24c25
diff --git a/Android.bp b/Android.bp
index e7d12ee..7991095 100644
--- a/Android.bp
+++ b/Android.bp
@@ -820,6 +820,11 @@
   name: "perfetto_include_perfetto_ext_ipc_ipc",
 }
 
+// GN: //include/perfetto/ext/trace_processor:export_json
+filegroup {
+  name: "perfetto_include_perfetto_ext_trace_processor_export_json",
+}
+
 // GN: //include/perfetto/ext/traced:sys_stats_counters
 filegroup {
   name: "perfetto_include_perfetto_ext_traced_sys_stats_counters",
@@ -5284,6 +5289,7 @@
     ":perfetto_include_perfetto_base_base",
     ":perfetto_include_perfetto_ext_base_base",
     ":perfetto_include_perfetto_ext_ipc_ipc",
+    ":perfetto_include_perfetto_ext_trace_processor_export_json",
     ":perfetto_include_perfetto_ext_traced_sys_stats_counters",
     ":perfetto_include_perfetto_ext_traced_traced",
     ":perfetto_include_perfetto_ext_tracing_core_core",
@@ -5563,6 +5569,7 @@
   srcs: [
     ":perfetto_include_perfetto_base_base",
     ":perfetto_include_perfetto_ext_base_base",
+    ":perfetto_include_perfetto_ext_trace_processor_export_json",
     ":perfetto_include_perfetto_ext_traced_sys_stats_counters",
     ":perfetto_include_perfetto_protozero_protozero",
     ":perfetto_include_perfetto_trace_processor_trace_processor",
@@ -5657,6 +5664,7 @@
   srcs: [
     ":perfetto_include_perfetto_base_base",
     ":perfetto_include_perfetto_ext_base_base",
+    ":perfetto_include_perfetto_ext_trace_processor_export_json",
     ":perfetto_include_perfetto_ext_traced_sys_stats_counters",
     ":perfetto_include_perfetto_profiling_symbolizer",
     ":perfetto_include_perfetto_protozero_protozero",
diff --git a/BUILD b/BUILD
index 0965d30..4e0f8ee 100644
--- a/BUILD
+++ b/BUILD
@@ -273,6 +273,14 @@
     ],
 )
 
+# GN target: //include/perfetto/ext/trace_processor:export_json
+filegroup(
+    name = "include_perfetto_ext_trace_processor_export_json",
+    srcs = [
+        "include/perfetto/ext/trace_processor/export_json.h",
+    ],
+)
+
 # GN target: //include/perfetto/ext/traced:sys_stats_counters
 filegroup(
     name = "include_perfetto_ext_traced_sys_stats_counters",
@@ -2453,6 +2461,7 @@
     hdrs = [
         ":include_perfetto_base_base",
         ":include_perfetto_ext_base_base",
+        ":include_perfetto_ext_trace_processor_export_json",
         ":include_perfetto_ext_traced_sys_stats_counters",
         ":include_perfetto_protozero_protozero",
         ":include_perfetto_trace_processor_trace_processor",
@@ -2505,6 +2514,7 @@
         "src/trace_processor/trace_processor_shell.cc",
         ":include_perfetto_base_base",
         ":include_perfetto_ext_base_base",
+        ":include_perfetto_ext_trace_processor_export_json",
         ":include_perfetto_ext_traced_sys_stats_counters",
         ":include_perfetto_protozero_protozero",
         ":include_perfetto_trace_processor_trace_processor",
@@ -2607,6 +2617,7 @@
     hdrs = [
         ":include_perfetto_base_base",
         ":include_perfetto_ext_base_base",
+        ":include_perfetto_ext_trace_processor_export_json",
         ":include_perfetto_ext_traced_sys_stats_counters",
         ":include_perfetto_profiling_symbolizer",
         ":include_perfetto_protozero_protozero",
@@ -2682,6 +2693,7 @@
     srcs = [
         ":include_perfetto_base_base",
         ":include_perfetto_ext_base_base",
+        ":include_perfetto_ext_trace_processor_export_json",
         ":include_perfetto_ext_traced_sys_stats_counters",
         ":include_perfetto_profiling_symbolizer",
         ":include_perfetto_protozero_protozero",
diff --git a/BUILD.gn b/BUILD.gn
index be4b48c..7557952 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -233,6 +233,7 @@
     configs -= [ "//build/config/compiler:chromium_code" ]
     configs += [ "//build/config/compiler:no_chromium_code" ]
     public_deps = [
+      "include/perfetto/ext/trace_processor:export_json",
       "include/perfetto/trace_processor",
     ]
   }
diff --git a/include/perfetto/ext/trace_processor/BUILD.gn b/include/perfetto/ext/trace_processor/BUILD.gn
new file mode 100644
index 0000000..a2fd7fa
--- /dev/null
+++ b/include/perfetto/ext/trace_processor/BUILD.gn
@@ -0,0 +1,23 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("../../../../gn/perfetto.gni")
+
+# Exposed for Chromium only. May be removed in the future.
+source_set("export_json") {
+  sources = []
+  if (enable_perfetto_trace_processor_json) {
+    sources += [ "export_json.h" ]
+  }
+}
diff --git a/include/perfetto/ext/trace_processor/export_json.h b/include/perfetto/ext/trace_processor/export_json.h
new file mode 100644
index 0000000..b0c8812
--- /dev/null
+++ b/include/perfetto/ext/trace_processor/export_json.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_EXT_TRACE_PROCESSOR_EXPORT_JSON_H_
+#define INCLUDE_PERFETTO_EXT_TRACE_PROCESSOR_EXPORT_JSON_H_
+
+#include <stdio.h>
+
+#include <functional>
+
+#include "perfetto/base/export.h"
+#include "perfetto/trace_processor/status.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace json {
+
+class TraceProcessor;
+
+using ArgumentNameFilterPredicate = std::function<bool(const char* arg_name)>;
+using ArgumentFilterPredicate =
+    std::function<bool(const char* category_group_name,
+                       const char* event_name,
+                       ArgumentNameFilterPredicate*)>;
+using MetadataFilterPredicate = std::function<bool(const char* metadata_name)>;
+using LabelFilterPredicate = std::function<bool(const char* label_name)>;
+
+class OutputWriter {
+ public:
+  OutputWriter();
+  virtual ~OutputWriter();
+
+  virtual util::Status AppendString(const std::string&) = 0;
+};
+
+// Public for Chrome. Exports the trace loaded in TraceProcessor to json,
+// applying argument, metadata and label filtering using the callbacks.
+util::Status PERFETTO_EXPORT ExportJson(TraceProcessor*,
+                                        OutputWriter*,
+                                        ArgumentFilterPredicate = nullptr,
+                                        MetadataFilterPredicate = nullptr,
+                                        LabelFilterPredicate = nullptr);
+
+}  // namespace json
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // INCLUDE_PERFETTO_EXT_TRACE_PROCESSOR_EXPORT_JSON_H_
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index b1905e9..0918bd2 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -177,6 +177,7 @@
     "../../gn:default_deps",
     "../../gn:sqlite",
     "../../gn:zlib",
+    "../../include/perfetto/ext/trace_processor:export_json",
     "../../include/perfetto/ext/traced:sys_stats_counters",
     "../../protos/perfetto/common:zero",
     "../../protos/perfetto/config:zero",
diff --git a/src/trace_processor/export_json.cc b/src/trace_processor/export_json.cc
index 67ef29d..2bd2197 100644
--- a/src/trace_processor/export_json.cc
+++ b/src/trace_processor/export_json.cc
@@ -17,6 +17,9 @@
 #include "perfetto/base/build_config.h"
 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
 
+#include "perfetto/ext/trace_processor/export_json.h"
+#include "src/trace_processor/export_json.h"
+
 #include <inttypes.h>
 #include <json/reader.h>
 #include <json/value.h>
@@ -26,8 +29,9 @@
 #include <vector>
 
 #include "perfetto/ext/base/string_splitter.h"
-#include "src/trace_processor/export_json.h"
 #include "src/trace_processor/metadata.h"
+#include "src/trace_processor/trace_processor_context.h"
+#include "src/trace_processor/trace_processor_impl.h"
 #include "src/trace_processor/trace_storage.h"
 
 namespace perfetto {
@@ -63,9 +67,27 @@
   return id == kNullStringId ? "" : storage->GetString(id).c_str();
 }
 
+class FileWriter : public OutputWriter {
+ public:
+  FileWriter(FILE* file) : file_(file) {}
+  ~FileWriter() override { fflush(file_); }
+
+  util::Status AppendString(const std::string& s) override {
+    size_t written =
+        fwrite(s.data(), sizeof(std::string::value_type), s.size(), file_);
+    if (written != s.size())
+      return util::ErrStatus("Error writing to file: %d", ferror(file_));
+    return util::OkStatus();
+  }
+
+ private:
+  FILE* file_;
+};
+
 class TraceFormatWriter {
  public:
-  TraceFormatWriter(FILE* output) : output_(output), first_event_(true) {
+  TraceFormatWriter(OutputWriter* output)
+      : output_(output), first_event_(true) {
     WriteHeader();
   }
 
@@ -73,10 +95,10 @@
 
   void WriteCommonEvent(const Json::Value& event) {
     if (!first_event_) {
-      fputs(",", output_);
+      output_->AppendString(",");
     }
     Json::FastWriter writer;
-    fputs(writer.write(event).c_str(), output_);
+    output_->AppendString(writer.write(event));
     first_event_ = false;
   }
 
@@ -85,7 +107,7 @@
                           uint32_t tid,
                           uint32_t pid) {
     if (!first_event_) {
-      fputs(",", output_);
+      output_->AppendString(",");
     }
     Json::FastWriter writer;
     Json::Value value;
@@ -100,7 +122,7 @@
     args["name"] = metadata_value;
     value["args"] = args;
 
-    fputs(writer.write(value).c_str(), output_);
+    output_->AppendString(writer.write(value));
     first_event_ = false;
   }
 
@@ -144,7 +166,7 @@
   void AddUserTraceData(const std::string& data) { user_trace_data_ += data; }
 
  private:
-  void WriteHeader() { fputs("{\"traceEvents\":[\n", output_); }
+  void WriteHeader() { output_->AppendString("{\"traceEvents\":[\n"); }
 
   void WriteFooter() {
     Json::FastWriter writer;
@@ -159,20 +181,19 @@
             user_trace_data_.c_str());
       }
     }
-    fputs("]", output_);
+    output_->AppendString("]");
     if (!system_trace_data_.empty()) {
-      fputs(",\"systemTraceEvents\":\n", output_);
-      fputs(writer.write(Json::Value(system_trace_data_)).c_str(), output_);
+      output_->AppendString(",\"systemTraceEvents\":\n");
+      output_->AppendString(writer.write(Json::Value(system_trace_data_)));
     }
     if (!metadata_.empty()) {
-      fputs(",\"metadata\":\n", output_);
-      fputs(writer.write(metadata_).c_str(), output_);
+      output_->AppendString(",\"metadata\":\n");
+      output_->AppendString(writer.write(metadata_));
     }
-    fputs("}", output_);
-    fflush(output_);
+    output_->AppendString("}");
   }
 
-  FILE* output_;
+  OutputWriter* output_;
   bool first_event_;
   Json::Value metadata_;
   std::string system_trace_data_;
@@ -315,8 +336,8 @@
   }
 }
 
-ResultCode ExportThreadNames(const TraceStorage* storage,
-                             TraceFormatWriter* writer) {
+util::Status ExportThreadNames(const TraceStorage* storage,
+                               TraceFormatWriter* writer) {
   for (UniqueTid i = 1; i < storage->thread_count(); ++i) {
     auto thread = storage->GetThread(i);
     if (!thread.name_id.is_null()) {
@@ -325,11 +346,11 @@
       writer->WriteMetadataEvent("thread_name", thread_name, thread.tid, pid);
     }
   }
-  return kResultOk;
+  return util::OkStatus();
 }
 
-ResultCode ExportProcessNames(const TraceStorage* storage,
-                              TraceFormatWriter* writer) {
+util::Status ExportProcessNames(const TraceStorage* storage,
+                                TraceFormatWriter* writer) {
   for (UniquePid i = 1; i < storage->process_count(); ++i) {
     auto process = storage->GetProcess(i);
     if (!process.name_id.is_null()) {
@@ -337,12 +358,12 @@
       writer->WriteMetadataEvent("process_name", process_name, 0, process.pid);
     }
   }
-  return kResultOk;
+  return util::OkStatus();
 }
 
-ResultCode ExportSlices(const TraceStorage* storage,
-                        const ArgsBuilder& args_builder,
-                        TraceFormatWriter* writer) {
+util::Status ExportSlices(const TraceStorage* storage,
+                          const ArgsBuilder& args_builder,
+                          TraceFormatWriter* writer) {
   const auto& slices = storage->nestable_slices();
   for (uint32_t i = 0; i < slices.slice_count(); ++i) {
     Json::Value event;
@@ -472,12 +493,14 @@
         } else if (slices.types()[i] == RefType::kRefNoRef) {
           event["s"] = "g";
         } else {
-          return kResultWrongRefType;
+          return util::ErrStatus("unknown ref type: %d",
+                                 static_cast<int>(slices.types()[i]));
         }
         writer->WriteCommonEvent(event);
       } else {  // Complete event.
         if (slices.types()[i] != RefType::kRefUtid) {
-          return kResultWrongRefType;
+          return util::ErrStatus("unknown ref type: %d",
+                                 static_cast<int>(slices.types()[i]));
         }
         if (duration_ns > 0) {
           event["ph"] = "X";
@@ -509,7 +532,7 @@
       }
     }
   }
-  return kResultOk;
+  return util::OkStatus();
 }
 
 Json::Value ConvertLegacyRawEventToJson(const TraceStorage* storage,
@@ -587,9 +610,9 @@
   return event;
 }
 
-ResultCode ExportRawEvents(const TraceStorage* storage,
-                           const ArgsBuilder& args_builder,
-                           TraceFormatWriter* writer) {
+util::Status ExportRawEvents(const TraceStorage* storage,
+                             const ArgsBuilder& args_builder,
+                             TraceFormatWriter* writer) {
   base::Optional<StringId> raw_legacy_event_key_id =
       storage->string_pool().GetId("track_event.legacy_event");
   base::Optional<StringId> raw_legacy_system_trace_event_id =
@@ -621,11 +644,11 @@
       writer->MergeMetadata(args);
     }
   }
-  return kResultOk;
+  return util::OkStatus();
 }
 
-ResultCode ExportCpuProfileSamples(const TraceStorage* storage,
-                                   TraceFormatWriter* writer) {
+util::Status ExportCpuProfileSamples(const TraceStorage* storage,
+                                     TraceFormatWriter* writer) {
   const TraceStorage::CpuProfileStackSamples& samples =
       storage->cpu_profile_stack_samples();
   for (uint32_t i = 0; i < samples.size(); ++i) {
@@ -695,11 +718,11 @@
     writer->WriteCommonEvent(event);
   }
 
-  return kResultOk;
+  return util::OkStatus();
 }
 
-ResultCode ExportMetadata(const TraceStorage* storage,
-                          TraceFormatWriter* writer) {
+util::Status ExportMetadata(const TraceStorage* storage,
+                            TraceFormatWriter* writer) {
   const auto& trace_metadata = storage->metadata();
   const auto& keys = trace_metadata.keys();
   const auto& values = trace_metadata.values();
@@ -761,10 +784,11 @@
         break;
     }
   }
-  return kResultOk;
+  return util::OkStatus();
 }
 
-ResultCode ExportStats(const TraceStorage* storage, TraceFormatWriter* writer) {
+util::Status ExportStats(const TraceStorage* storage,
+                         TraceFormatWriter* writer) {
   const auto& stats = storage->stats();
 
   writer->SetPerfettoStats("producers_connected",
@@ -833,44 +857,68 @@
       "trace_writer_packet_loss",
       stats[stats::traced_buf_trace_writer_packet_loss].indexed_values);
 
-  return kResultOk;
+  return util::OkStatus();
+}
+
+util::Status ExportJson(const TraceStorage* storage,
+                        OutputWriter* output,
+                        ArgumentFilterPredicate /*argument_filter*/,
+                        MetadataFilterPredicate /*metadata_filter*/,
+                        LabelFilterPredicate /*label_filter*/) {
+  // TODO(eseckler): Implement argument/metadata/label filtering.
+  TraceFormatWriter writer(output);
+  ArgsBuilder args_builder(storage);
+
+  util::Status status = ExportThreadNames(storage, &writer);
+  if (!status.ok())
+    return status;
+
+  status = ExportProcessNames(storage, &writer);
+  if (!status.ok())
+    return status;
+
+  status = ExportSlices(storage, args_builder, &writer);
+  if (!status.ok())
+    return status;
+
+  status = ExportRawEvents(storage, args_builder, &writer);
+  if (!status.ok())
+    return status;
+
+  status = ExportCpuProfileSamples(storage, &writer);
+  if (!status.ok())
+    return status;
+
+  status = ExportMetadata(storage, &writer);
+  if (!status.ok())
+    return status;
+
+  status = ExportStats(storage, &writer);
+  if (!status.ok())
+    return status;
+
+  return util::OkStatus();
 }
 
 }  // namespace
 
-ResultCode ExportJson(const TraceStorage* storage, FILE* output) {
-  TraceFormatWriter writer(output);
-  ArgsBuilder args_builder(storage);
+OutputWriter::OutputWriter() = default;
+OutputWriter::~OutputWriter() = default;
 
-  ResultCode code = ExportThreadNames(storage, &writer);
-  if (code != kResultOk)
-    return code;
+util::Status ExportJson(TraceProcessor* tp,
+                        OutputWriter* output,
+                        ArgumentFilterPredicate argument_filter,
+                        MetadataFilterPredicate metadata_filter,
+                        LabelFilterPredicate label_filter) {
+  const TraceStorage* storage =
+      reinterpret_cast<TraceProcessorImpl*>(tp)->context()->storage.get();
+  return ExportJson(storage, output, argument_filter, metadata_filter,
+                    label_filter);
+}
 
-  code = ExportProcessNames(storage, &writer);
-  if (code != kResultOk)
-    return code;
-
-  code = ExportSlices(storage, args_builder, &writer);
-  if (code != kResultOk)
-    return code;
-
-  code = ExportRawEvents(storage, args_builder, &writer);
-  if (code != kResultOk)
-    return code;
-
-  code = ExportCpuProfileSamples(storage, &writer);
-  if (code != kResultOk)
-    return code;
-
-  code = ExportMetadata(storage, &writer);
-  if (code != kResultOk)
-    return code;
-
-  code = ExportStats(storage, &writer);
-  if (code != kResultOk)
-    return code;
-
-  return kResultOk;
+util::Status ExportJson(const TraceStorage* storage, FILE* output) {
+  FileWriter writer(output);
+  return ExportJson(storage, &writer, nullptr, nullptr, nullptr);
 }
 
 }  // namespace json
diff --git a/src/trace_processor/export_json.h b/src/trace_processor/export_json.h
index 0ceefd8..df7a687 100644
--- a/src/trace_processor/export_json.h
+++ b/src/trace_processor/export_json.h
@@ -17,21 +17,17 @@
 #ifndef SRC_TRACE_PROCESSOR_EXPORT_JSON_H_
 #define SRC_TRACE_PROCESSOR_EXPORT_JSON_H_
 
-#include "src/trace_processor/trace_storage.h"
-
 #include <stdio.h>
 
+#include "perfetto/trace_processor/status.h"
+#include "src/trace_processor/trace_storage.h"
+
 namespace perfetto {
 namespace trace_processor {
 namespace json {
 
-enum ResultCode {
-  kResultOk = 0,
-  kResultWrongRefType = 1,
-};
-
-// Export trace to a stream in json format.
-ResultCode ExportJson(const TraceStorage* storage, FILE* output);
+// Export trace to a file stream in json format.
+util::Status ExportJson(const TraceStorage*, FILE* output);
 
 }  // namespace json
 }  // namespace trace_processor
diff --git a/src/trace_processor/export_json_unittest.cc b/src/trace_processor/export_json_unittest.cc
index 51e1b57..cb30877 100644
--- a/src/trace_processor/export_json_unittest.cc
+++ b/src/trace_processor/export_json_unittest.cc
@@ -46,9 +46,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -82,9 +82,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -130,9 +130,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -164,9 +164,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -191,9 +191,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultWrongRefType);
+  EXPECT_FALSE(status.ok());
 }
 
 TEST(ExportJsonTest, StorageWithMetadata) {
@@ -239,9 +239,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -288,8 +288,8 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
-  EXPECT_EQ(code, kResultOk);
+  util::Status status = ExportJson(&storage, output);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -328,8 +328,8 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(storage, output);
-  EXPECT_EQ(code, kResultOk);
+  util::Status status = ExportJson(storage, output);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -367,9 +367,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -420,9 +420,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(storage, output);
+  util::Status status = ExportJson(storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -471,9 +471,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -517,9 +517,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -562,9 +562,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -608,9 +608,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -649,9 +649,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -678,9 +678,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -726,9 +726,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -784,9 +784,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -841,9 +841,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -891,9 +891,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(&storage, output);
+  util::Status status = ExportJson(&storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -978,9 +978,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(storage, output);
+  util::Status status = ExportJson(storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -1039,9 +1039,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(storage, output);
+  util::Status status = ExportJson(storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -1109,9 +1109,9 @@
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
-  int code = ExportJson(storage, output);
+  util::Status status = ExportJson(storage, output);
 
-  EXPECT_EQ(code, kResultOk);
+  EXPECT_TRUE(status.ok());
 
   Json::Reader reader;
   Json::Value result;
@@ -1130,6 +1130,9 @@
             "bar_module_name [bar_module_id]\n");
 }
 
+// TODO(eseckler): Add some tests that exercise the public ExportJson API and
+// argument / metadata / label filters.
+
 }  // namespace
 }  // namespace json
 }  // namespace trace_processor
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index eeec130..d81bc0a 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -229,14 +229,10 @@
     }
   }
 
-  json::ResultCode result = json::ExportJson(storage, output);
-  switch (result) {
-    case json::kResultOk:
-      return;
-    case json::kResultWrongRefType:
-      sqlite3_result_error(ctx, "Encountered a slice with unsupported ref type",
-                           -1);
-      return;
+  util::Status result = json::ExportJson(storage, output);
+  if (!result.ok()) {
+    sqlite3_result_error(ctx, result.message().c_str(), -1);
+    return;
   }
 }
 
diff --git a/src/trace_processor/trace_processor_impl.h b/src/trace_processor/trace_processor_impl.h
index a9cea90..0f61c2b 100644
--- a/src/trace_processor/trace_processor_impl.h
+++ b/src/trace_processor/trace_processor_impl.h
@@ -67,6 +67,8 @@
 
   void InterruptQuery() override;
 
+  TraceProcessorContext* context() { return &context_; }
+
  private:
   // Needed for iterators to be able to delete themselves from the vector.
   friend class IteratorImpl;