Create and use RtcEventLogOutput for output

We need to support two modes of writing to the output:
1. Current way - the application lets lets WebRTC know which file to write to, and WebRTC is then in charge of the writing.
2. New way - the application would receive indications from WebRTC about (encoded) RTC events, and would itself be in charge of processing them (be it writing it to a file, uploading it somewhere, etc.).

We achieve this by creating an interface for output - RtcEventLogOutput. By providing an instance of the subclass, RtcEventLogOutputFile, the old behavior is achieved. The subclass of the new behavior is to be added by a later CL.

TBR=stefan@webrtc.org

Bug: webrtc:8111
Change-Id: I9c50521a7f7144d86d8353a65995795862e19c44
Reviewed-on: https://webrtc-review.googlesource.com/2686
Commit-Queue: Elad Alon <eladalon@webrtc.org>
Reviewed-by: Elad Alon <eladalon@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20135}
diff --git a/logging/rtc_event_log/output/rtc_event_log_output_file.cc b/logging/rtc_event_log/output/rtc_event_log_output_file.cc
new file mode 100644
index 0000000..2f8b81c
--- /dev/null
+++ b/logging/rtc_event_log/output/rtc_event_log_output_file.cc
@@ -0,0 +1,113 @@
+/*
+ *  Copyright (c) 2017 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 <limits>
+
+#include "logging/rtc_event_log/output/rtc_event_log_output_file.h"
+#include "logging/rtc_event_log/rtc_event_log.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+#include "system_wrappers/include/file_wrapper.h"
+
+namespace webrtc {
+
+// Together with the assumption of no single Write() would ever be called on
+// an input with length greater-than-or-equal-to (max(size_t) / 2), this
+// guarantees no overflow of the check for remaining file capacity in Write().
+// This does *not* apply to files with unlimited size.
+const size_t RtcEventLogOutputFile::kMaxReasonableFileSize =
+    std::numeric_limits<size_t>::max() / 2;
+
+RtcEventLogOutputFile::RtcEventLogOutputFile(const std::string& file_name)
+    : RtcEventLogOutputFile(file_name, RtcEventLog::kUnlimitedOutput) {}
+
+RtcEventLogOutputFile::RtcEventLogOutputFile(const std::string& file_name,
+                                             size_t max_size_bytes)
+    : max_size_bytes_(max_size_bytes), file_(FileWrapper::Create()) {
+  RTC_CHECK_LE(max_size_bytes_, kMaxReasonableFileSize);
+
+  if (!file_->OpenFile(file_name.c_str(), false)) {
+    LOG(LS_ERROR) << "Can't open file. WebRTC event log not started.";
+    file_.reset();
+    return;
+  }
+}
+
+RtcEventLogOutputFile::RtcEventLogOutputFile(rtc::PlatformFile file)
+    : RtcEventLogOutputFile(file, RtcEventLog::kUnlimitedOutput) {}
+
+RtcEventLogOutputFile::RtcEventLogOutputFile(rtc::PlatformFile file,
+                                             size_t max_size_bytes)
+    : max_size_bytes_(max_size_bytes), file_(FileWrapper::Create()) {
+  RTC_CHECK_LE(max_size_bytes_, kMaxReasonableFileSize);
+
+  FILE* file_handle = rtc::FdopenPlatformFileForWriting(file);
+  if (!file_handle) {
+    LOG(LS_ERROR) << "Can't open file. WebRTC event log not started.";
+    // Even though we failed to open a FILE*, the file is still open
+    // and needs to be closed.
+    if (!rtc::ClosePlatformFile(file)) {
+      LOG(LS_ERROR) << "Can't close file.";
+      file_.reset();
+    }
+    return;
+  }
+
+  if (!file_->OpenFromFileHandle(file_handle)) {
+    LOG(LS_ERROR) << "Can't open file. WebRTC event log not started.";
+    file_.reset();
+    return;
+  }
+}
+
+RtcEventLogOutputFile::~RtcEventLogOutputFile() {
+  if (file_) {
+    RTC_DCHECK(IsActiveInternal());
+    file_->CloseFile();
+    file_.reset();
+  }
+}
+
+bool RtcEventLogOutputFile::IsActive() const {
+  return IsActiveInternal();
+}
+
+bool RtcEventLogOutputFile::Write(const std::string& output) {
+  RTC_DCHECK(IsActiveInternal());
+  // No single write may be so big, that it would risk overflowing the
+  // calculation of (written_bytes_ + output.length()).
+  RTC_DCHECK_LT(output.length(), kMaxReasonableFileSize);
+
+  bool written = false;
+  if (max_size_bytes_ == RtcEventLog::kUnlimitedOutput ||
+      written_bytes_ + output.length() <= max_size_bytes_) {
+    written = file_->Write(output.c_str(), output.size());
+    if (!written) {
+      LOG(LS_ERROR) << "FileWrapper failed to write WebRtcEventLog file.";
+    }
+  } else {
+    LOG(LS_VERBOSE) << "Max file size reached.";
+  }
+
+  if (written) {
+    written_bytes_ += output.size();
+  } else {
+    file_->CloseFile();
+    file_.reset();
+  }
+
+  return written;
+}
+
+bool RtcEventLogOutputFile::IsActiveInternal() const {
+  return file_ && file_->is_open();
+}
+
+}  // namespace webrtc