Adds functionality to write logs to memory.
This makes it possible to save log outputs from scenario tests to
either files or memory.
Bug: webrtc:9510
Change-Id: I883bd8240ab712d31d54118adf979041bd83481a
Reviewed-on: https://webrtc-review.googlesource.com/c/116321
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Per Kjellander <perkj@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26284}
diff --git a/api/rtc_event_log_output.h b/api/rtc_event_log_output.h
index 4a46324..92fb9e8 100644
--- a/api/rtc_event_log_output.h
+++ b/api/rtc_event_log_output.h
@@ -32,6 +32,9 @@
// after the first time |false| is returned. Write() may not be called on
// an inactive output sink.
virtual bool Write(const std::string& output) = 0;
+
+ // Indicates that buffers should be written to disk if applicable.
+ virtual void Flush() {}
};
} // namespace webrtc
diff --git a/modules/congestion_controller/BUILD.gn b/modules/congestion_controller/BUILD.gn
index 6857b5f..4cbe732 100644
--- a/modules/congestion_controller/BUILD.gn
+++ b/modules/congestion_controller/BUILD.gn
@@ -101,6 +101,7 @@
"../../api/units:time_delta",
"../../api/units:timestamp",
"../../rtc_base:checks",
+ "../../test/logging:log_writer",
"//third_party/abseil-cpp/absl/types:optional",
]
}
diff --git a/modules/congestion_controller/bbr/BUILD.gn b/modules/congestion_controller/bbr/BUILD.gn
index 0430a45..a6183be 100644
--- a/modules/congestion_controller/bbr/BUILD.gn
+++ b/modules/congestion_controller/bbr/BUILD.gn
@@ -128,6 +128,7 @@
"..:test_controller_printer",
"../../../api/transport:network_control",
"../../../api/units:timestamp",
+ "../../../logging:rtc_event_log_api",
"../../../rtc_base:checks",
]
}
diff --git a/modules/congestion_controller/bbr/test/bbr_printer.cc b/modules/congestion_controller/bbr/test/bbr_printer.cc
index c2eb578..3249493 100644
--- a/modules/congestion_controller/bbr/test/bbr_printer.cc
+++ b/modules/congestion_controller/bbr/test/bbr_printer.cc
@@ -24,15 +24,17 @@
return controller_ != nullptr;
}
-void BbrStatePrinter::PrintHeaders(FILE* out) {
- fprintf(out, "bbr_mode bbr_recovery_state round_trip_count gain_cycle_index");
+void BbrStatePrinter::PrintHeaders(RtcEventLogOutput* out) {
+ LogWriteFormat(
+ out, "bbr_mode bbr_recovery_state round_trip_count gain_cycle_index");
}
-void BbrStatePrinter::PrintValues(FILE* out) {
+void BbrStatePrinter::PrintValues(RtcEventLogOutput* out) {
RTC_CHECK(controller_);
bbr::BbrNetworkController::DebugState debug(*controller_);
- fprintf(out, "%i %i %i %i", debug.mode, debug.recovery_state,
- static_cast<int>(debug.round_trip_count), debug.gain_cycle_index);
+ LogWriteFormat(out, "%i %i %i %i", debug.mode, debug.recovery_state,
+ static_cast<int>(debug.round_trip_count),
+ debug.gain_cycle_index);
}
NetworkControlUpdate BbrStatePrinter::GetState(Timestamp at_time) const {
diff --git a/modules/congestion_controller/bbr/test/bbr_printer.h b/modules/congestion_controller/bbr/test/bbr_printer.h
index 84a765e..c2b2843 100644
--- a/modules/congestion_controller/bbr/test/bbr_printer.h
+++ b/modules/congestion_controller/bbr/test/bbr_printer.h
@@ -16,6 +16,7 @@
#include "api/transport/network_control.h"
#include "api/transport/network_types.h"
#include "api/units/timestamp.h"
+#include "logging/rtc_event_log/rtc_event_log.h"
#include "modules/congestion_controller/bbr/bbr_factory.h"
#include "modules/congestion_controller/bbr/bbr_network_controller.h"
#include "modules/congestion_controller/test/controller_printer.h"
@@ -28,8 +29,8 @@
void Attach(bbr::BbrNetworkController*);
bool Attached() const override;
- void PrintHeaders(FILE* out) override;
- void PrintValues(FILE* out) override;
+ void PrintHeaders(RtcEventLogOutput* out) override;
+ void PrintValues(RtcEventLogOutput* out) override;
NetworkControlUpdate GetState(Timestamp at_time) const override;
diff --git a/modules/congestion_controller/goog_cc/test/goog_cc_printer.cc b/modules/congestion_controller/goog_cc/test/goog_cc_printer.cc
index 717f554..c67f7e4 100644
--- a/modules/congestion_controller/goog_cc/test/goog_cc_printer.cc
+++ b/modules/congestion_controller/goog_cc/test/goog_cc_printer.cc
@@ -31,25 +31,26 @@
return controller_ != nullptr;
}
-void GoogCcStatePrinter::PrintHeaders(FILE* out) {
- fprintf(out,
- "rate_control_state rate_control_region alr_state"
- " trendline trendline_modified_offset trendline_offset_threshold");
+void GoogCcStatePrinter::PrintHeaders(RtcEventLogOutput* out) {
+ out->Write(
+ "rate_control_state rate_control_region alr_state"
+ " trendline trendline_modified_offset trendline_offset_threshold");
}
-void GoogCcStatePrinter::PrintValues(FILE* out) {
+void GoogCcStatePrinter::PrintValues(RtcEventLogOutput* out) {
RTC_CHECK(controller_);
auto* detector = controller_->delay_based_bwe_->delay_detector_.get();
auto* trendline_estimator = reinterpret_cast<TrendlineEstimator*>(detector);
- fprintf(out, "%i %f %i %.6lf %.6lf %.6lf",
- controller_->delay_based_bwe_->rate_control_.rate_control_state_,
- controller_->delay_based_bwe_->rate_control_.link_capacity_
- .estimate_kbps_.value_or(NAN) *
- 1000 / 8,
- controller_->alr_detector_->alr_started_time_ms_.has_value(),
- trendline_estimator->prev_trend_,
- trendline_estimator->prev_modified_trend_,
- trendline_estimator->threshold_);
+ LogWriteFormat(
+ out, "%i %f %i %.6lf %.6lf %.6lf",
+ controller_->delay_based_bwe_->rate_control_.rate_control_state_,
+ controller_->delay_based_bwe_->rate_control_.link_capacity_.estimate_kbps_
+ .value_or(NAN) *
+ 1000 / 8,
+ controller_->alr_detector_->alr_started_time_ms_.has_value(),
+ trendline_estimator->prev_trend_,
+ trendline_estimator->prev_modified_trend_,
+ trendline_estimator->threshold_);
}
NetworkControlUpdate GoogCcStatePrinter::GetState(Timestamp at_time) const {
diff --git a/modules/congestion_controller/goog_cc/test/goog_cc_printer.h b/modules/congestion_controller/goog_cc/test/goog_cc_printer.h
index b254db4..173c6c3 100644
--- a/modules/congestion_controller/goog_cc/test/goog_cc_printer.h
+++ b/modules/congestion_controller/goog_cc/test/goog_cc_printer.h
@@ -29,8 +29,8 @@
void Attach(GoogCcNetworkController*);
bool Attached() const override;
- void PrintHeaders(FILE* out) override;
- void PrintValues(FILE* out) override;
+ void PrintHeaders(RtcEventLogOutput* out) override;
+ void PrintValues(RtcEventLogOutput* out) override;
NetworkControlUpdate GetState(Timestamp at_time) const override;
diff --git a/modules/congestion_controller/test/controller_printer.cc b/modules/congestion_controller/test/controller_printer.cc
index a23a5ab..9b3cb59 100644
--- a/modules/congestion_controller/test/controller_printer.cc
+++ b/modules/congestion_controller/test/controller_printer.cc
@@ -20,20 +20,20 @@
namespace webrtc {
ControlStatePrinter::ControlStatePrinter(
- FILE* output,
+ std::unique_ptr<RtcEventLogOutput> output,
std::unique_ptr<DebugStatePrinter> debug_printer)
- : output_(output), debug_printer_(std::move(debug_printer)) {}
+ : output_(std::move(output)), debug_printer_(std::move(debug_printer)) {}
ControlStatePrinter::~ControlStatePrinter() = default;
void ControlStatePrinter::PrintHeaders() {
- fprintf(output_, "time bandwidth rtt target pacing padding window");
+ output_->Write("time bandwidth rtt target pacing padding window");
if (debug_printer_) {
- fprintf(output_, " ");
- debug_printer_->PrintHeaders(output_);
+ output_->Write(" ");
+ debug_printer_->PrintHeaders(output_.get());
}
- fprintf(output_, "\n");
- fflush(output_);
+ output_->Write("\n");
+ output_->Flush();
}
void ControlStatePrinter::PrintState(const Timestamp time,
@@ -48,16 +48,16 @@
double congestion_window = state.congestion_window
? state.congestion_window->bytes<double>()
: std::numeric_limits<double>::infinity();
-
- fprintf(output_, "%f %f %f %f %f %f %f", timestamp, bandwidth, rtt,
- target_rate, pacing_rate, padding_rate, congestion_window);
+ LogWriteFormat(output_.get(), "%f %f %f %f %f %f %f", timestamp, bandwidth,
+ rtt, target_rate, pacing_rate, padding_rate,
+ congestion_window);
if (debug_printer_) {
- fprintf(output_, " ");
- debug_printer_->PrintValues(output_);
+ output_->Write(" ");
+ debug_printer_->PrintValues(output_.get());
}
- fprintf(output_, "\n");
- fflush(output_);
+ output_->Write("\n");
+ output_->Flush();
}
void ControlStatePrinter::PrintState(const Timestamp time) {
diff --git a/modules/congestion_controller/test/controller_printer.h b/modules/congestion_controller/test/controller_printer.h
index d619157..f88d50b 100644
--- a/modules/congestion_controller/test/controller_printer.h
+++ b/modules/congestion_controller/test/controller_printer.h
@@ -10,25 +10,25 @@
#ifndef MODULES_CONGESTION_CONTROLLER_TEST_CONTROLLER_PRINTER_H_
#define MODULES_CONGESTION_CONTROLLER_TEST_CONTROLLER_PRINTER_H_
-#include <cstdio>
#include <memory>
#include "api/transport/network_types.h"
#include "api/units/timestamp.h"
+#include "test/logging/log_writer.h"
namespace webrtc {
class DebugStatePrinter {
public:
virtual bool Attached() const = 0;
- virtual void PrintHeaders(FILE* out) = 0;
- virtual void PrintValues(FILE* out) = 0;
+ virtual void PrintHeaders(RtcEventLogOutput* out) = 0;
+ virtual void PrintValues(RtcEventLogOutput* out) = 0;
virtual NetworkControlUpdate GetState(Timestamp at_time) const = 0;
virtual ~DebugStatePrinter() = default;
};
class ControlStatePrinter {
public:
- ControlStatePrinter(FILE* output,
+ ControlStatePrinter(std::unique_ptr<RtcEventLogOutput> output,
std::unique_ptr<DebugStatePrinter> debug_printer);
~ControlStatePrinter();
void PrintHeaders();
@@ -36,7 +36,7 @@
void PrintState(const Timestamp time);
private:
- FILE* output_;
+ std::unique_ptr<RtcEventLogOutput> output_;
std::unique_ptr<DebugStatePrinter> debug_printer_;
};
} // namespace webrtc
diff --git a/test/logging/BUILD.gn b/test/logging/BUILD.gn
new file mode 100644
index 0000000..f588925
--- /dev/null
+++ b/test/logging/BUILD.gn
@@ -0,0 +1,33 @@
+# Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import("../../webrtc.gni")
+
+rtc_source_set("log_writer") {
+ testonly = true
+ visibility = [ "*" ]
+ sources = [
+ "file_log_writer.cc",
+ "file_log_writer.h",
+ "log_writer.cc",
+ "log_writer.h",
+ "memory_log_writer.cc",
+ "memory_log_writer.h",
+ ]
+
+ deps = [
+ "../../api:libjingle_logging_api",
+ "../../rtc_base:checks",
+ "../../rtc_base:logging",
+ "../../rtc_base:rtc_base_tests_utils",
+ "../../rtc_base:stringutils",
+ "../../test:fileutils",
+ "//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+}
diff --git a/test/logging/file_log_writer.cc b/test/logging/file_log_writer.cc
new file mode 100644
index 0000000..f8c32f4
--- /dev/null
+++ b/test/logging/file_log_writer.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "test/logging/file_log_writer.h"
+
+#include "absl/memory/memory.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "test/testsupport/fileutils.h"
+
+namespace webrtc {
+namespace webrtc_impl {
+
+FileLogWriter::FileLogWriter(std::string file_path)
+ : out_(std::fopen(file_path.c_str(), "wb")) {
+ RTC_CHECK(out_ != nullptr)
+ << "Failed to open file: '" << file_path << "' for writing.";
+}
+
+FileLogWriter::~FileLogWriter() {
+ std::fclose(out_);
+}
+
+bool FileLogWriter::IsActive() const {
+ return true;
+}
+
+bool FileLogWriter::Write(const std::string& value) {
+ // We don't expect the write to fail. If it does, we don't want to risk
+ // silently ignoring it.
+ RTC_CHECK_EQ(std::fwrite(value.data(), 1, value.size(), out_), value.size())
+ << "fwrite failed unexpectedly: " << errno;
+ return true;
+}
+
+void FileLogWriter::Flush() {
+ RTC_CHECK_EQ(fflush(out_), 0) << "fflush failed unexpectedly: " << errno;
+}
+
+} // namespace webrtc_impl
+
+FileLogWriterFactory::FileLogWriterFactory(std::string base_path)
+ : base_path_(base_path) {
+ for (size_t i = 0; i < base_path.size(); ++i) {
+ if (base_path[i] == '/')
+ test::CreateDir(base_path.substr(0, i));
+ }
+}
+
+FileLogWriterFactory::~FileLogWriterFactory() {}
+
+std::unique_ptr<RtcEventLogOutput> FileLogWriterFactory::Create(
+ std::string filename) {
+ return absl::make_unique<webrtc_impl::FileLogWriter>(base_path_ + filename);
+}
+} // namespace webrtc
diff --git a/test/logging/file_log_writer.h b/test/logging/file_log_writer.h
new file mode 100644
index 0000000..e3c0cf6
--- /dev/null
+++ b/test/logging/file_log_writer.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef TEST_LOGGING_FILE_LOG_WRITER_H_
+#define TEST_LOGGING_FILE_LOG_WRITER_H_
+
+#include <cstdio>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "test/logging/log_writer.h"
+
+namespace webrtc {
+namespace webrtc_impl {
+class FileLogWriter final : public RtcEventLogOutput {
+ public:
+ explicit FileLogWriter(std::string file_path);
+ ~FileLogWriter() final;
+ bool IsActive() const override;
+ bool Write(const std::string& value) override;
+ void Flush() override;
+
+ private:
+ std::FILE* const out_;
+};
+} // namespace webrtc_impl
+class FileLogWriterFactory final : public LogWriterFactoryInterface {
+ public:
+ explicit FileLogWriterFactory(std::string base_path);
+ ~FileLogWriterFactory() final;
+
+ std::unique_ptr<RtcEventLogOutput> Create(std::string filename) override;
+
+ private:
+ const std::string base_path_;
+ std::vector<std::unique_ptr<webrtc_impl::FileLogWriter>> writers_;
+};
+
+} // namespace webrtc
+
+#endif // TEST_LOGGING_FILE_LOG_WRITER_H_
diff --git a/test/logging/log_writer.cc b/test/logging/log_writer.cc
new file mode 100644
index 0000000..a20d026
--- /dev/null
+++ b/test/logging/log_writer.cc
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "test/logging/log_writer.h"
+
+namespace webrtc {
+
+LogWriterFactoryAddPrefix::LogWriterFactoryAddPrefix(
+ LogWriterFactoryInterface* base,
+ std::string prefix)
+ : base_factory_(base), prefix_(prefix) {}
+
+std::unique_ptr<RtcEventLogOutput> LogWriterFactoryAddPrefix::Create(
+ std::string filename) {
+ return base_factory_->Create(prefix_ + filename);
+}
+
+} // namespace webrtc
diff --git a/test/logging/log_writer.h b/test/logging/log_writer.h
new file mode 100644
index 0000000..8946cec
--- /dev/null
+++ b/test/logging/log_writer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef TEST_LOGGING_LOG_WRITER_H_
+#define TEST_LOGGING_LOG_WRITER_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "api/rtceventlogoutput.h"
+#include "rtc_base/strings/string_builder.h"
+
+namespace webrtc {
+template <class... Args>
+inline void LogWriteFormat(RtcEventLogOutput* out_, const char* fmt, ...) {
+ va_list args, copy;
+ va_start(args, fmt);
+ va_copy(copy, args);
+ const int predicted_length = std::vsnprintf(nullptr, 0, fmt, copy);
+ va_end(copy);
+
+ RTC_DCHECK_GE(predicted_length, 0);
+ std::string out_str(predicted_length, '\0');
+ if (predicted_length > 0) {
+ // Pass "+ 1" to vsnprintf to include space for the '\0'.
+ const int actual_length =
+ std::vsnprintf(&out_str.front(), predicted_length + 1, fmt, args);
+ RTC_DCHECK_GE(actual_length, 0);
+ }
+ va_end(args);
+ out_->Write(out_str);
+}
+
+class LogWriterFactoryInterface {
+ public:
+ virtual std::unique_ptr<RtcEventLogOutput> Create(std::string filename) = 0;
+ virtual ~LogWriterFactoryInterface() = default;
+};
+
+class LogWriterFactoryAddPrefix : public LogWriterFactoryInterface {
+ public:
+ LogWriterFactoryAddPrefix(LogWriterFactoryInterface* base,
+ std::string prefix);
+ std::unique_ptr<RtcEventLogOutput> Create(std::string filename) override;
+
+ private:
+ LogWriterFactoryInterface* const base_factory_;
+ const std::string prefix_;
+};
+
+} // namespace webrtc
+
+#endif // TEST_LOGGING_LOG_WRITER_H_
diff --git a/test/logging/memory_log_writer.cc b/test/logging/memory_log_writer.cc
new file mode 100644
index 0000000..92945ed
--- /dev/null
+++ b/test/logging/memory_log_writer.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#include "test/logging/memory_log_writer.h"
+
+#include "absl/memory/memory.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+namespace webrtc {
+namespace {
+class MemoryLogWriter final : public RtcEventLogOutput {
+ public:
+ explicit MemoryLogWriter(std::map<std::string, std::string>* target,
+ std::string filename)
+ : target_(target), filename_(filename) {}
+ ~MemoryLogWriter() final {
+ size_t size;
+ buffer_.GetSize(&size);
+ target_->insert({filename_, std::string(buffer_.GetBuffer(), size)});
+ }
+ bool IsActive() const override { return true; }
+ bool Write(const std::string& value) override {
+ size_t written;
+ int error;
+ return buffer_.Write(value.data(), value.size(), &written, &error) ==
+ rtc::SR_SUCCESS;
+ }
+ void Flush() override {}
+
+ private:
+ std::map<std::string, std::string>* const target_;
+ const std::string filename_;
+ rtc::MemoryStream buffer_;
+};
+
+class MemoryLogWriterFactory : public LogWriterFactoryInterface {
+ public:
+ explicit MemoryLogWriterFactory(std::map<std::string, std::string>* target)
+ : target_(target) {}
+ ~MemoryLogWriterFactory() final {}
+ std::unique_ptr<RtcEventLogOutput> Create(std::string filename) override {
+ return absl::make_unique<MemoryLogWriter>(target_, filename);
+ }
+
+ private:
+ std::map<std::string, std::string>* const target_;
+};
+
+} // namespace
+
+MemoryLogStorage::MemoryLogStorage() {}
+
+MemoryLogStorage::~MemoryLogStorage() {}
+
+std::unique_ptr<LogWriterFactoryInterface> MemoryLogStorage::CreateFactory() {
+ return absl::make_unique<MemoryLogWriterFactory>(&logs_);
+}
+
+// namespace webrtc_impl
+} // namespace webrtc
diff --git a/test/logging/memory_log_writer.h b/test/logging/memory_log_writer.h
new file mode 100644
index 0000000..daef297
--- /dev/null
+++ b/test/logging/memory_log_writer.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef TEST_LOGGING_MEMORY_LOG_WRITER_H_
+#define TEST_LOGGING_MEMORY_LOG_WRITER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "rtc_base/memory_stream.h"
+#include "test/logging/log_writer.h"
+
+namespace webrtc {
+
+// Allows creating log writer factories that creates log writers that saves
+// their content to memory. When the log writers are destroyed, their content is
+// saved to the logs_ member of this class. The intended usage is to keep this
+// class alive after the created factories and writers have been destroyed and
+// then use logs() to access all the saved logs.
+class MemoryLogStorage {
+ public:
+ MemoryLogStorage();
+ ~MemoryLogStorage();
+ std::unique_ptr<LogWriterFactoryInterface> CreateFactory();
+ const std::map<std::string, std::string>& logs() { return logs_; }
+
+ private:
+ std::map<std::string, std::string> logs_;
+};
+
+} // namespace webrtc
+
+#endif // TEST_LOGGING_MEMORY_LOG_WRITER_H_
diff --git a/test/scenario/BUILD.gn b/test/scenario/BUILD.gn
index feb09d4..ff7ada6 100644
--- a/test/scenario/BUILD.gn
+++ b/test/scenario/BUILD.gn
@@ -95,6 +95,7 @@
"../../system_wrappers",
"../../system_wrappers:field_trial",
"../../video",
+ "../logging:log_writer",
"network:emulated_network",
"//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/types:optional",
diff --git a/test/scenario/call_client.cc b/test/scenario/call_client.cc
index 866df06..feb50b0 100644
--- a/test/scenario/call_client.cc
+++ b/test/scenario/call_client.cc
@@ -12,7 +12,6 @@
#include <utility>
#include "absl/memory/memory.h"
-#include "logging/rtc_event_log/output/rtc_event_log_output_file.h"
#include "modules/audio_mixer/audio_mixer_impl.h"
#include "modules/congestion_controller/goog_cc/test/goog_cc_printer.h"
#include "test/call_test.h"
@@ -57,39 +56,38 @@
}
LoggingNetworkControllerFactory::LoggingNetworkControllerFactory(
- std::string filename,
+ LogWriterFactoryInterface* log_writer_factory,
TransportControllerConfig config) {
- if (filename.empty()) {
+ std::unique_ptr<RtcEventLogOutput> cc_out;
+ if (!log_writer_factory) {
event_log_ = RtcEventLog::CreateNull();
} else {
event_log_ = RtcEventLog::Create(RtcEventLog::EncodingType::Legacy);
bool success = event_log_->StartLogging(
- absl::make_unique<RtcEventLogOutputFile>(filename + ".rtc.dat",
- RtcEventLog::kUnlimitedOutput),
- RtcEventLog::kImmediateOutput);
+ log_writer_factory->Create(".rtc.dat"), RtcEventLog::kImmediateOutput);
RTC_CHECK(success);
- cc_out_ = fopen((filename + ".cc_state.txt").c_str(), "w");
+ cc_out = log_writer_factory->Create(".cc_state.txt");
}
switch (config.cc) {
case TransportControllerConfig::CongestionController::kGoogCc:
- if (cc_out_) {
+ if (cc_out) {
auto goog_printer = absl::make_unique<GoogCcStatePrinter>();
owned_cc_factory_.reset(
new GoogCcDebugFactory(event_log_.get(), goog_printer.get()));
- cc_printer_.reset(
- new ControlStatePrinter(cc_out_, std::move(goog_printer)));
+ cc_printer_.reset(new ControlStatePrinter(std::move(cc_out),
+ std::move(goog_printer)));
} else {
owned_cc_factory_.reset(
new GoogCcNetworkControllerFactory(event_log_.get()));
}
break;
case TransportControllerConfig::CongestionController::kGoogCcFeedback:
- if (cc_out_) {
+ if (cc_out) {
auto goog_printer = absl::make_unique<GoogCcStatePrinter>();
owned_cc_factory_.reset(new GoogCcFeedbackDebugFactory(
event_log_.get(), goog_printer.get()));
- cc_printer_.reset(
- new ControlStatePrinter(cc_out_, std::move(goog_printer)));
+ cc_printer_.reset(new ControlStatePrinter(std::move(cc_out),
+ std::move(goog_printer)));
} else {
owned_cc_factory_.reset(
new GoogCcFeedbackNetworkControllerFactory(event_log_.get()));
@@ -97,7 +95,7 @@
break;
case TransportControllerConfig::CongestionController::kInjected:
cc_factory_ = config.cc_factory;
- if (cc_out_)
+ if (cc_out)
RTC_LOG(LS_WARNING)
<< "Can't log controller state for injected network controllers";
break;
@@ -111,8 +109,6 @@
}
LoggingNetworkControllerFactory::~LoggingNetworkControllerFactory() {
- if (cc_out_)
- fclose(cc_out_);
}
void LoggingNetworkControllerFactory::LogCongestionControllerStats(
@@ -134,13 +130,13 @@
return cc_factory_->GetProcessInterval();
}
-CallClient::CallClient(Clock* clock,
- std::string name,
- std::string log_filename,
- CallClientConfig config)
+CallClient::CallClient(
+ Clock* clock,
+ std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
+ CallClientConfig config)
: clock_(clock),
- name_(name),
- network_controller_factory_(log_filename, config.transport),
+ log_writer_factory_(std::move(log_writer_factory)),
+ network_controller_factory_(log_writer_factory_.get(), config.transport),
fake_audio_setup_(InitAudio()),
call_(CreateCall(config,
&network_controller_factory_,
@@ -189,6 +185,12 @@
packet.arrival_time.us());
}
+std::unique_ptr<RtcEventLogOutput> CallClient::GetLogWriter(std::string name) {
+ if (!log_writer_factory_ || name.empty())
+ return nullptr;
+ return log_writer_factory_->Create(name);
+}
+
uint32_t CallClient::GetNextVideoSsrc() {
RTC_CHECK_LT(next_video_ssrc_index_, CallTest::kNumSsrcs);
return CallTest::kVideoSendSsrcs[next_video_ssrc_index_++];
diff --git a/test/scenario/call_client.h b/test/scenario/call_client.h
index ace6366..793e16d 100644
--- a/test/scenario/call_client.h
+++ b/test/scenario/call_client.h
@@ -19,6 +19,7 @@
#include "modules/congestion_controller/test/controller_printer.h"
#include "modules/rtp_rtcp/include/rtp_header_parser.h"
#include "rtc_base/constructor_magic.h"
+#include "test/logging/log_writer.h"
#include "test/scenario/column_printer.h"
#include "test/scenario/network/network_emulation.h"
#include "test/scenario/network_node.h"
@@ -30,7 +31,7 @@
class LoggingNetworkControllerFactory
: public NetworkControllerFactoryInterface {
public:
- LoggingNetworkControllerFactory(std::string filename,
+ LoggingNetworkControllerFactory(LogWriterFactoryInterface* log_writer_factory,
TransportControllerConfig config);
RTC_DISALLOW_COPY_AND_ASSIGN(LoggingNetworkControllerFactory);
~LoggingNetworkControllerFactory();
@@ -46,7 +47,6 @@
std::unique_ptr<NetworkControllerFactoryInterface> owned_cc_factory_;
NetworkControllerFactoryInterface* cc_factory_ = nullptr;
std::unique_ptr<ControlStatePrinter> cc_printer_;
- FILE* cc_out_ = nullptr;
};
struct CallClientFakeAudio {
@@ -60,8 +60,7 @@
class CallClient : public EmulatedNetworkReceiverInterface {
public:
CallClient(Clock* clock,
- std::string name,
- std::string log_filename,
+ std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
CallClientConfig config);
RTC_DISALLOW_COPY_AND_ASSIGN(CallClient);
@@ -73,6 +72,7 @@
}
void OnPacketReceived(EmulatedIpPacket packet) override;
+ std::unique_ptr<RtcEventLogOutput> GetLogWriter(std::string name);
private:
friend class Scenario;
@@ -91,7 +91,7 @@
void AddExtensions(std::vector<RtpExtension> extensions);
Clock* clock_;
- const std::string name_;
+ const std::unique_ptr<LogWriterFactoryInterface> log_writer_factory_;
LoggingNetworkControllerFactory network_controller_factory_;
CallClientFakeAudio fake_audio_setup_;
std::unique_ptr<Call> call_;
diff --git a/test/scenario/column_printer.cc b/test/scenario/column_printer.cc
index 234c919..ab70af9 100644
--- a/test/scenario/column_printer.cc
+++ b/test/scenario/column_printer.cc
@@ -34,38 +34,26 @@
return ColumnPrinter(headers, printer, max_length);
}
-StatesPrinter::StatesPrinter(std::string filename,
+StatesPrinter::StatesPrinter(std::unique_ptr<RtcEventLogOutput> writer,
std::vector<ColumnPrinter> printers)
- : StatesPrinter(printers) {
- if (!filename.empty()) {
- output_file_ = fopen(filename.c_str(), "w");
- RTC_CHECK(output_file_);
- output_ = output_file_;
- }
-}
-
-StatesPrinter::StatesPrinter(std::vector<ColumnPrinter> printers)
- : printers_(printers) {
- output_ = stdout;
+ : writer_(std::move(writer)), printers_(printers) {
RTC_CHECK(!printers_.empty());
for (auto& printer : printers_)
buffer_size_ += printer.max_length_ + 1;
buffer_.resize(buffer_size_);
}
-StatesPrinter::~StatesPrinter() {
- if (output_file_)
- fclose(output_file_);
-}
+StatesPrinter::~StatesPrinter() = default;
void StatesPrinter::PrintHeaders() {
- if (!output_file_)
+ if (!writer_)
return;
- fprintf(output_, "%s", printers_[0].headers_);
+ writer_->Write(printers_[0].headers_);
for (size_t i = 1; i < printers_.size(); ++i) {
- fprintf(output_, " %s", printers_[i].headers_);
+ writer_->Write(" ");
+ writer_->Write(printers_[i].headers_);
}
- fputs("\n", output_);
+ writer_->Write("\n");
}
void StatesPrinter::PrintRow() {
@@ -77,9 +65,9 @@
sb << ' ';
printers_[i].printer_(sb);
}
- sb << "\n\0";
- if (output_file_)
- fputs(&buffer_.front(), output_);
+ sb << "\n";
+ if (writer_)
+ writer_->Write(std::string(sb.str(), sb.size()));
}
} // namespace test
} // namespace webrtc
diff --git a/test/scenario/column_printer.h b/test/scenario/column_printer.h
index 5ac9a1b..4ace50d 100644
--- a/test/scenario/column_printer.h
+++ b/test/scenario/column_printer.h
@@ -16,6 +16,7 @@
#include "rtc_base/constructor_magic.h"
#include "rtc_base/strings/string_builder.h"
+#include "test/logging/log_writer.h"
namespace webrtc {
namespace test {
@@ -43,19 +44,18 @@
class StatesPrinter {
public:
- StatesPrinter(std::string filename, std::vector<ColumnPrinter> printers);
- explicit StatesPrinter(std::vector<ColumnPrinter> printers);
+ StatesPrinter(std::unique_ptr<RtcEventLogOutput> writer,
+ std::vector<ColumnPrinter> printers);
RTC_DISALLOW_COPY_AND_ASSIGN(StatesPrinter);
~StatesPrinter();
void PrintHeaders();
void PrintRow();
private:
+ const std::unique_ptr<RtcEventLogOutput> writer_;
const std::vector<ColumnPrinter> printers_;
size_t buffer_size_ = 0;
std::vector<char> buffer_;
- FILE* output_file_ = nullptr;
- FILE* output_ = nullptr;
};
} // namespace test
} // namespace webrtc
diff --git a/test/scenario/quality_stats.cc b/test/scenario/quality_stats.cc
index 2c73437..863cf1f 100644
--- a/test/scenario/quality_stats.cc
+++ b/test/scenario/quality_stats.cc
@@ -19,12 +19,10 @@
namespace test {
VideoQualityAnalyzer::VideoQualityAnalyzer(
- std::string filename_or_empty,
+ std::unique_ptr<RtcEventLogOutput> writer,
std::function<void(const VideoFrameQualityInfo&)> frame_info_handler)
- : task_queue_("VideoAnalyzer") {
- if (!filename_or_empty.empty()) {
- output_file_ = fopen(filename_or_empty.c_str(), "w");
- RTC_CHECK(output_file_);
+ : writer_(std::move(writer)), task_queue_("VideoAnalyzer") {
+ if (writer_) {
PrintHeaders();
frame_info_handlers_.push_back(
[this](const VideoFrameQualityInfo& info) { PrintFrameInfo(info); });
@@ -37,8 +35,6 @@
rtc::Event event;
task_queue_.PostTask([&event] { event.Set(); });
event.Wait(rtc::Event::kForever);
- if (output_file_)
- fclose(output_file_);
}
void VideoQualityAnalyzer::OnCapturedFrame(const VideoFrame& frame) {
@@ -114,15 +110,15 @@
}
void VideoQualityAnalyzer::PrintHeaders() {
- fprintf(output_file_, "capt recv_capt render width height psnr\n");
+ writer_->Write("capt recv_capt render width height psnr\n");
}
void VideoQualityAnalyzer::PrintFrameInfo(const VideoFrameQualityInfo& sample) {
- fprintf(output_file_, "%.3f %.3f %.3f %i %i %.3f\n",
- sample.capture_time.seconds<double>(),
- sample.received_capture_time.seconds<double>(),
- sample.render_time.seconds<double>(), sample.width, sample.height,
- sample.psnr);
+ LogWriteFormat(writer_.get(), "%.3f %.3f %.3f %i %i %.3f\n",
+ sample.capture_time.seconds<double>(),
+ sample.received_capture_time.seconds<double>(),
+ sample.render_time.seconds<double>(), sample.width,
+ sample.height, sample.psnr);
}
void VideoQualityStats::HandleFrameInfo(VideoFrameQualityInfo sample) {
diff --git a/test/scenario/quality_stats.h b/test/scenario/quality_stats.h
index 34702ac..18dc4f75 100644
--- a/test/scenario/quality_stats.h
+++ b/test/scenario/quality_stats.h
@@ -11,6 +11,7 @@
#define TEST_SCENARIO_QUALITY_STATS_H_
#include <deque>
+#include <memory>
#include <string>
#include <vector>
@@ -22,6 +23,7 @@
#include "rtc_base/task_queue.h"
#include "rtc_base/time_utils.h"
#include "system_wrappers/include/clock.h"
+#include "test/logging/log_writer.h"
#include "test/scenario/quality_info.h"
#include "test/scenario/scenario_config.h"
#include "test/statistics.h"
@@ -32,7 +34,7 @@
class VideoQualityAnalyzer {
public:
VideoQualityAnalyzer(
- std::string filename_or_empty,
+ std::unique_ptr<RtcEventLogOutput> writer,
std::function<void(const VideoFrameQualityInfo&)> frame_info_handler);
~VideoQualityAnalyzer();
void OnCapturedFrame(const VideoFrame& frame);
@@ -46,12 +48,12 @@
int64_t CapturedFrameCaptureTimeOffsetMs(const VideoFrame& captured) const;
void PrintHeaders();
void PrintFrameInfo(const VideoFrameQualityInfo& sample);
+ const std::unique_ptr<RtcEventLogOutput> writer_;
std::vector<std::function<void(const VideoFrameQualityInfo&)>>
frame_info_handlers_;
std::deque<VideoFrame> captured_frames_;
absl::optional<int64_t> first_capture_ntp_time_ms_;
absl::optional<uint32_t> first_decode_rtp_timestamp_;
- FILE* output_file_ = nullptr;
rtc::TaskQueue task_queue_;
};
diff --git a/test/scenario/scenario.cc b/test/scenario/scenario.cc
index 0efe80c..49125a0 100644
--- a/test/scenario/scenario.cc
+++ b/test/scenario/scenario.cc
@@ -11,10 +11,12 @@
#include <algorithm>
+#include "absl/memory/memory.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
#include "rtc_base/flags.h"
#include "rtc_base/socket_address.h"
+#include "test/logging/file_log_writer.h"
#include "test/scenario/network/network_emulation.h"
#include "test/testsupport/file_utils.h"
@@ -27,6 +29,19 @@
namespace test {
namespace {
int64_t kMicrosPerSec = 1000000;
+std::unique_ptr<FileLogWriterFactory> GetScenarioLogManager(
+ std::string file_name) {
+ if (FLAG_scenario_logs && !file_name.empty()) {
+ std::string output_root = FLAG_out_root;
+ if (output_root.empty())
+ output_root = OutputPath() + "output_data/";
+
+ auto base_filename = output_root + file_name + ".";
+ RTC_LOG(LS_INFO) << "Saving scenario logs to: " << base_filename;
+ return absl::make_unique<FileLogWriterFactory>(base_filename);
+ }
+ return nullptr;
+}
}
RepeatedActivity::RepeatedActivity(TimeDelta interval,
@@ -54,30 +69,24 @@
return last_update_ + interval_;
}
-Scenario::Scenario() : Scenario("", true) {}
+Scenario::Scenario()
+ : Scenario(std::unique_ptr<LogWriterFactoryInterface>(), true) {}
Scenario::Scenario(std::string file_name) : Scenario(file_name, true) {}
Scenario::Scenario(std::string file_name, bool real_time)
- : real_time_mode_(real_time),
+ : Scenario(GetScenarioLogManager(file_name), real_time) {}
+
+Scenario::Scenario(
+ std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
+ bool real_time)
+ : log_writer_factory_(std::move(log_writer_factory)),
+ real_time_mode_(real_time),
sim_clock_(100000 * kMicrosPerSec),
clock_(real_time ? Clock::GetRealTimeClock() : &sim_clock_),
audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()),
audio_encoder_factory_(CreateBuiltinAudioEncoderFactory()) {
- if (FLAG_scenario_logs && !file_name.empty()) {
- std::string output_root = FLAG_out_root;
- if (output_root.empty())
- output_root = OutputPath() + "output_data/";
- if (output_root.back() == '/')
- CreateDir(output_root);
- for (size_t i = 0; i < file_name.size(); ++i) {
- if (file_name[i] == '/')
- CreateDir(output_root + file_name.substr(0, i));
- }
- base_filename_ = output_root + file_name;
- RTC_LOG(LS_INFO) << "Saving scenario logs to: " << base_filename_;
- }
- if (!real_time_mode_ && !base_filename_.empty()) {
+ if (!real_time_mode_ && log_writer_factory_) {
rtc::SetClockForTesting(&event_log_fake_clock_);
event_log_fake_clock_.SetTimeNanos(sim_clock_.TimeInMicroseconds() * 1000);
}
@@ -105,8 +114,7 @@
std::vector<ColumnPrinter> all_printers{TimePrinter()};
for (auto& printer : printers)
all_printers.push_back(printer);
- StatesPrinter* printer =
- new StatesPrinter(GetFullPathOrEmpty(name), all_printers);
+ StatesPrinter* printer = new StatesPrinter(GetLogWriter(name), all_printers);
printers_.emplace_back(printer);
printer->PrintHeaders();
if (interval.IsFinite())
@@ -117,7 +125,7 @@
CallClient* Scenario::CreateClient(std::string name, CallClientConfig config) {
RTC_DCHECK(real_time_mode_);
CallClient* client =
- new CallClient(clock_, name, GetFullPathOrEmpty(name), config);
+ new CallClient(clock_, GetLogWriterFactory(name), config);
if (config.transport.state_log_interval.IsFinite()) {
Every(config.transport.state_log_interval, [this, client]() {
client->network_controller_factory_.LogCongestionControllerStats(Now());
@@ -182,9 +190,9 @@
uint64_t send_id = next_route_id_++;
uint64_t return_id = next_route_id_++;
SimulatedTimeClient* client = new SimulatedTimeClient(
- GetFullPathOrEmpty(name), config, stream_configs, send_link, return_link,
+ GetLogWriterFactory(name), config, stream_configs, send_link, return_link,
send_id, return_id, Now());
- if (!base_filename_.empty() && !name.empty() &&
+ if (log_writer_factory_ && !name.empty() &&
config.transport.state_log_interval.IsFinite()) {
Every(config.transport.state_log_interval, [this, client]() {
client->network_controller_factory_.LogCongestionControllerStats(Now());
@@ -283,12 +291,11 @@
VideoStreamPair* Scenario::CreateVideoStream(
std::pair<CallClient*, CallClient*> clients,
VideoStreamConfig config) {
- std::string quality_log_file_name;
+ std::unique_ptr<RtcEventLogOutput> quality_logger;
if (config.analyzer.log_to_file)
- quality_log_file_name =
- GetFullPathOrEmpty(clients.first->name_ + ".video_quality.txt");
+ quality_logger = clients.first->GetLogWriter(".video_quality.txt");
video_streams_.emplace_back(new VideoStreamPair(
- clients.first, clients.second, config, quality_log_file_name));
+ clients.first, clients.second, config, std::move(quality_logger)));
return video_streams_.back().get();
}
@@ -364,7 +371,7 @@
sim_clock_.AdvanceTimeMicroseconds(wait_time.us());
// The fake clock is quite slow to update, we only update it if logging is
// turned on to save time.
- if (!base_filename_.empty())
+ if (!log_writer_factory_)
event_log_fake_clock_.SetTimeNanos(sim_clock_.TimeInMicroseconds() *
1000);
}
diff --git a/test/scenario/scenario.h b/test/scenario/scenario.h
index f566840..c3fc877 100644
--- a/test/scenario/scenario.h
+++ b/test/scenario/scenario.h
@@ -14,8 +14,10 @@
#include <utility>
#include <vector>
+#include "absl/memory/memory.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/fake_clock.h"
+#include "test/logging/log_writer.h"
#include "test/scenario/audio_stream.h"
#include "test/scenario/call_client.h"
#include "test/scenario/column_printer.h"
@@ -63,6 +65,8 @@
Scenario();
explicit Scenario(std::string file_name);
Scenario(std::string file_name, bool real_time);
+ Scenario(std::unique_ptr<LogWriterFactoryInterface> log_writer_manager,
+ bool real_time);
RTC_DISALLOW_COPY_AND_ASSIGN(Scenario);
~Scenario();
@@ -163,15 +167,22 @@
// Return the duration of the current session so far.
TimeDelta Duration();
- std::string GetFullPathOrEmpty(std::string name) const {
- if (base_filename_.empty() || name.empty())
- return std::string();
- return base_filename_ + "." + name;
+ std::unique_ptr<RtcEventLogOutput> GetLogWriter(std::string name) {
+ if (!log_writer_factory_ || name.empty())
+ return nullptr;
+ return log_writer_factory_->Create(name);
+ }
+ std::unique_ptr<LogWriterFactoryInterface> GetLogWriterFactory(
+ std::string name) {
+ if (!log_writer_factory_ || name.empty())
+ return nullptr;
+ return absl::make_unique<LogWriterFactoryAddPrefix>(
+ log_writer_factory_.get(), name);
}
private:
NullReceiver null_receiver_;
- std::string base_filename_;
+ std::unique_ptr<LogWriterFactoryInterface> log_writer_factory_;
const bool real_time_mode_;
SimulatedClock sim_clock_;
Clock* clock_;
diff --git a/test/scenario/simulated_time.cc b/test/scenario/simulated_time.cc
index 18dff32..af4acc3 100644
--- a/test/scenario/simulated_time.cc
+++ b/test/scenario/simulated_time.cc
@@ -245,7 +245,7 @@
}
SimulatedTimeClient::SimulatedTimeClient(
- std::string log_filename,
+ std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
SimulatedTimeClientConfig config,
std::vector<PacketStreamConfig> stream_configs,
std::vector<EmulatedNetworkNode*> send_link,
@@ -253,7 +253,8 @@
uint64_t send_receiver_id,
uint64_t return_receiver_id,
Timestamp at_time)
- : network_controller_factory_(log_filename, config.transport),
+ : log_writer_factory_(std::move(log_writer_factory)),
+ network_controller_factory_(log_writer_factory_.get(), config.transport),
send_link_(send_link),
return_link_(return_link),
sender_(send_link.front(), send_receiver_id),
@@ -274,11 +275,10 @@
CongestionProcess(at_time);
network_controller_factory_.LogCongestionControllerStats(at_time);
- if (!log_filename.empty()) {
- std::string packet_log_name = log_filename + ".packets.txt";
- packet_log_ = fopen(packet_log_name.c_str(), "w");
- fprintf(packet_log_,
- "transport_seq packet_size send_time recv_time feed_time\n");
+ if (log_writer_factory_) {
+ packet_log_ = log_writer_factory_->Create(".packets.txt");
+ packet_log_->Write(
+ "transport_seq packet_size send_time recv_time feed_time\n");
}
}
@@ -289,18 +289,17 @@
packet.arrival_time);
for (PacketResult& feedback : report.packet_feedbacks) {
if (packet_log_)
- fprintf(packet_log_, "%" PRId64 " %" PRId64 " %.3lf %.3lf %.3lf\n",
- feedback.sent_packet.sequence_number,
- feedback.sent_packet.size.bytes(),
- feedback.sent_packet.send_time.seconds<double>(),
- feedback.receive_time.seconds<double>(),
- packet.arrival_time.seconds<double>());
+ LogWriteFormat(packet_log_.get(),
+ "%" PRId64 " %" PRId64 " %.3lf %.3lf %.3lf\n",
+ feedback.sent_packet.sequence_number,
+ feedback.sent_packet.size.bytes(),
+ feedback.sent_packet.send_time.seconds<double>(),
+ feedback.receive_time.seconds<double>(),
+ packet.arrival_time.seconds<double>());
}
Update(congestion_controller_->OnTransportPacketsFeedback(report));
}
SimulatedTimeClient::~SimulatedTimeClient() {
- if (packet_log_)
- fclose(packet_log_);
}
void SimulatedTimeClient::Update(NetworkControlUpdate update) {
diff --git a/test/scenario/simulated_time.h b/test/scenario/simulated_time.h
index a4cb70a..762748d 100644
--- a/test/scenario/simulated_time.h
+++ b/test/scenario/simulated_time.h
@@ -11,7 +11,6 @@
#define TEST_SCENARIO_SIMULATED_TIME_H_
#include <stdint.h>
-#include <stdio.h>
#include <deque>
#include <map>
#include <memory>
@@ -25,6 +24,7 @@
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "rtc_base/copy_on_write_buffer.h"
+#include "test/logging/log_writer.h"
#include "test/scenario/call_client.h"
#include "test/scenario/network_node.h"
#include "test/scenario/scenario_config.h"
@@ -120,14 +120,15 @@
// a more accurate simulation, use the real time only CallClient.
class SimulatedTimeClient : EmulatedNetworkReceiverInterface {
public:
- SimulatedTimeClient(std::string log_filename,
- SimulatedTimeClientConfig config,
- std::vector<PacketStreamConfig> stream_configs,
- std::vector<EmulatedNetworkNode*> send_link,
- std::vector<EmulatedNetworkNode*> return_link,
- uint64_t send_receiver_id,
- uint64_t return_receiver_id,
- Timestamp at_time);
+ SimulatedTimeClient(
+ std::unique_ptr<LogWriterFactoryInterface> log_writer_factory,
+ SimulatedTimeClientConfig config,
+ std::vector<PacketStreamConfig> stream_configs,
+ std::vector<EmulatedNetworkNode*> send_link,
+ std::vector<EmulatedNetworkNode*> return_link,
+ uint64_t send_receiver_id,
+ uint64_t return_receiver_id,
+ Timestamp at_time);
SimulatedTimeClient(const SimulatedTimeClient&) = delete;
~SimulatedTimeClient();
void Update(NetworkControlUpdate update);
@@ -144,6 +145,7 @@
private:
friend class Scenario;
+ std::unique_ptr<LogWriterFactoryInterface> log_writer_factory_;
LoggingNetworkControllerFactory network_controller_factory_;
std::unique_ptr<NetworkControllerInterface> congestion_controller_;
std::vector<EmulatedNetworkNode*> send_link_;
@@ -153,7 +155,7 @@
TargetRateConstraints current_contraints_;
DataRate target_rate_ = DataRate::Infinity();
DataRate link_capacity_ = DataRate::Infinity();
- FILE* packet_log_ = nullptr;
+ std::unique_ptr<RtcEventLogOutput> packet_log_;
std::vector<std::unique_ptr<PacketStream>> packet_streams_;
};
diff --git a/test/scenario/video_stream.cc b/test/scenario/video_stream.cc
index d427a90..429c494 100644
--- a/test/scenario/video_stream.cc
+++ b/test/scenario/video_stream.cc
@@ -399,12 +399,14 @@
VideoStreamPair::~VideoStreamPair() = default;
-VideoStreamPair::VideoStreamPair(CallClient* sender,
- CallClient* receiver,
- VideoStreamConfig config,
- std::string quality_log_file_name)
+VideoStreamPair::VideoStreamPair(
+ CallClient* sender,
+ CallClient* receiver,
+ VideoStreamConfig config,
+ std::unique_ptr<RtcEventLogOutput> quality_writer)
: config_(config),
- analyzer_(quality_log_file_name, config.analyzer.frame_quality_handler),
+ analyzer_(std::move(quality_writer),
+ config.analyzer.frame_quality_handler),
send_stream_(sender, config, &sender->transport_, &analyzer_),
receive_stream_(receiver,
config,
diff --git a/test/scenario/video_stream.h b/test/scenario/video_stream.h
index 23994be..e38e30e 100644
--- a/test/scenario/video_stream.h
+++ b/test/scenario/video_stream.h
@@ -16,6 +16,7 @@
#include "rtc_base/constructor_magic.h"
#include "test/fake_encoder.h"
#include "test/frame_generator_capturer.h"
+#include "test/logging/log_writer.h"
#include "test/scenario/call_client.h"
#include "test/scenario/column_printer.h"
#include "test/scenario/network_node.h"
@@ -104,7 +105,7 @@
VideoStreamPair(CallClient* sender,
CallClient* receiver,
VideoStreamConfig config,
- std::string quality_log_file_name);
+ std::unique_ptr<RtcEventLogOutput> quality_writer);
const VideoStreamConfig config_;