// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/client/in_memory_log_handler.h"

#include "base/check.h"
#include "base/containers/ring_buffer.h"
#include "base/logging.h"
#include "base/synchronization/lock.h"

namespace remoting {

namespace {

constexpr size_t kMaxNumberOfLogs = 1000;

struct LogHandlerContext {
  base::Lock lock;
  base::RingBuffer<std::string, kMaxNumberOfLogs> buffer;
};

// Leaky.
LogHandlerContext* g_log_handler_context = nullptr;

bool HandleLogMessage(int severity,
                      const char* file,
                      int line,
                      size_t message_start,
                      const std::string& str) {
  base::AutoLock auto_lock(g_log_handler_context->lock);
  g_log_handler_context->buffer.SaveToBuffer(str);

  // Pass log messages through the default logging pipeline.
  return false;
}

}  // namespace

// static
void InMemoryLogHandler::Register() {
  DCHECK(!g_log_handler_context);
  DCHECK(!logging::GetLogMessageHandler())
      << "Log message handler has already been set.";

  g_log_handler_context = new LogHandlerContext();

  base::AutoLock auto_lock(g_log_handler_context->lock);
  logging::SetLogMessageHandler(&HandleLogMessage);
}

// static
std::string InMemoryLogHandler::GetInMemoryLogs() {
  std::string output;

  base::AutoLock auto_lock(g_log_handler_context->lock);

  for (auto iter = g_log_handler_context->buffer.Begin(); iter; ++iter) {
    if (iter != g_log_handler_context->buffer.Begin()) {
      output += '\n';
    }
    // *iter returns a const std::string*.
    output += **iter;
  }
  return output;
}

}  // namespace remoting