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

#include "logger.h"

#include <lib/syslog/global.h>
#include <zircon/status.h>

namespace syslog {
namespace {

const char* StripDots(const char* path) {
  while (strncmp(path, "../", 3) == 0)
    path += 3;
  return path;
}

const char* StripPath(const char* path) {
  const char* p = strrchr(path, '/');
  if (p)
    return p + 1;
  else
    return path;
}

}  // namespace

namespace internal {

LogMessage::LogMessage(fx_log_severity_t severity, const char* file, int line, const char* tag,
                       zx_status_t status, const char* condition)
    : severity_(severity), file_(file), line_(line), tag_(tag), status_(status) {
  stream_ << (severity > FX_LOG_INFO ? StripDots(file_) : StripPath(file_)) << "(" << line_
          << "): ";

  if (condition)
    stream_ << "Check failed: " << condition << ": ";
}

void FxLogFatal() { abort(); }

LogMessage::~LogMessage() {
  fx_logger_t* logger = fx_log_get_logger();
  if (logger) {
    if (status_ != INT32_MAX) {
      stream_ << ": " << status_ << " (" << zx_status_get_string(status_) << ")";
    }

    fx_logger_log(logger, severity_, tag_, stream_.str().c_str());
  } else if (severity_ == FX_LOG_FATAL) {
    // FX_LOG_FATAL should abort regardless of whether a logger exists
    FxLogFatal();
  }
}

// Note that this implementation allows a data race on counter_, but
// we consider that harmless because, as specified by the comments on
// FX_LOGS_FIRST_N, we allow for the possibility that the message might get
// logged more than |n| times if a single callsite of that macro is invoked by
// multiple threads.
bool LogFirstNState::ShouldLog(int n) {
  const int32_t counter_value = counter_.load(std::memory_order_relaxed);
  if (counter_value < n) {
    counter_.store(counter_value + 1, std::memory_order_relaxed);
    return true;
  }
  return false;
}

}  // namespace internal
}  // namespace syslog
