Skip to content

Commit

Permalink
Add Logging SDK implementation for Logging API
Browse files Browse the repository at this point in the history
  • Loading branch information
Karen Xu committed Nov 16, 2020
1 parent fd8527b commit d33ffdb
Show file tree
Hide file tree
Showing 15 changed files with 566 additions and 0 deletions.
Empty file.
60 changes: 60 additions & 0 deletions sdk/include/opentelemetry/sdk/logs/logger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright The OpenTelemetry Authors
*
* 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.
*/

#pragma once

#include "opentelemetry/logs/log_record.h"
#include "opentelemetry/logs/logger.h"
#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/nostd/string_view.h"
#include "opentelemetry/sdk/common/atomic_shared_ptr.h"
#include "opentelemetry/sdk/logs/logger_provider.h"
#include "opentelemetry/sdk/logs/processor.h"

#include <unordered_map>
#include <vector>

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace logs
{
class LoggerProvider;

class Logger final : public opentelemetry::logs::Logger
{
public:
/**
* Initialize a new logger.
* @param logger_provider The logger provider that owns this logger.
*/
explicit Logger(std::shared_ptr<LoggerProvider> logger_provider) noexcept;

/**
* Writes a log record into the processor.
* @param record The record to write into the processor.
*/
void log(const opentelemetry::logs::LogRecord &record) noexcept override;

private:
// The logger provider of this Logger. Uses a weak_ptr to avoid cyclic dependancy issues the with
// logger provider
std::weak_ptr<LoggerProvider> logger_provider_;
};

} // namespace logs
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
101 changes: 101 additions & 0 deletions sdk/include/opentelemetry/sdk/logs/logger_provider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright The OpenTelemetry Authors
*
* 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.
*/

#pragma once

#include <memory>
#include <mutex>
#include <string>
#include <vector>

#include "opentelemetry/logs/logger_provider.h"
#include "opentelemetry/logs/noop.h"
#include "opentelemetry/nostd/shared_ptr.h"
#include "opentelemetry/sdk/common/atomic_shared_ptr.h"
#include "opentelemetry/sdk/logs/logger.h"
#include "opentelemetry/sdk/logs/processor.h"

// Define the maximum number of loggers that are allowed to be registered to the loggerprovider.
// TODO: Add link to logging spec once this is added to it
#define MAX_LOGGER_COUNT 100

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace logs
{
class Logger;

class LoggerProvider final : public opentelemetry::logs::LoggerProvider,
public std::enable_shared_from_this<LoggerProvider>
{
public:
/**
* Initialize a new logger provider. A processor must later be assigned
* to this logger provider via the SetProcessor() method.
*/
explicit LoggerProvider() noexcept;

/**
* Creates a logger with the given name, and returns a shared pointer to it.
* If a logger with that name already exists, return a shared pointer to it
* @param name The name of the logger to be created.
* @param options (OPTIONAL) The options for the logger. TODO: Once the logging spec defines it,
* give a list of options that the logger supports.
*/
opentelemetry::nostd::shared_ptr<opentelemetry::logs::Logger> GetLogger(
opentelemetry::nostd::string_view name,
opentelemetry::nostd::string_view options = "") noexcept override;

/**
* Creates a logger with the given name, and returns a shared pointer to it.
* If a logger with that name already exists, return a shared pointer to it
* @param name The name of the logger to be created.
* @param args (OPTIONAL) The arguments for the logger. TODO: Once the logging spec defines it,
* give a list of arguments that the logger supports.
*/
opentelemetry::nostd::shared_ptr<opentelemetry::logs::Logger> GetLogger(
opentelemetry::nostd::string_view name,
nostd::span<nostd::string_view> args) noexcept override;

/**
* Returns a shared pointer to the processor currently stored in the
* logger provider. If no processor exists, returns a nullptr
*/
std::shared_ptr<LogProcessor> GetProcessor() noexcept;

// Sets the common processor that all the Logger instances will use
/**
* Sets the processor that is stored internally in the logger provider.
* @param processor The processor to be stored inside the logger provider.
* This must not be a nullptr.
*/
void SetProcessor(std::shared_ptr<LogProcessor> processor) noexcept;

private:
// A pointer to the processor stored by this logger provider
opentelemetry::sdk::AtomicSharedPtr<LogProcessor> processor_;

// A vector of pointers to all the loggers that have been created
std::unordered_map<std::string, opentelemetry::nostd::shared_ptr<opentelemetry::logs::Logger>>
loggers_;

// A mutex that ensures only one thread is using the map of loggers
std::mutex mu_;
};
} // namespace logs
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
47 changes: 47 additions & 0 deletions sdk/include/opentelemetry/sdk/logs/processor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright The OpenTelemetry Authors
*
* 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.
*/

#pragma once

#include <chrono>
#include <memory>
#include "opentelemetry/logs/log_record.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace logs
{
/**
* This Log Processor is responsible for conversion of logs to exportable
* representation and passing them to exporters.
*/
class LogProcessor
{
public:
virtual ~LogProcessor() = default;

virtual void OnReceive(std::unique_ptr<opentelemetry::logs::LogRecord> &&record) noexcept = 0;

virtual void ForceFlush(
std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept = 0;

virtual void Shutdown(
std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept = 0;
};
} // namespace logs
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
1 change: 1 addition & 0 deletions sdk/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
add_subdirectory(common)
add_subdirectory(trace)
add_subdirectory(metrics)
add_subdirectory(logs)
26 changes: 26 additions & 0 deletions sdk/src/logs/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2020, OpenTelemetry Authors
#
# 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.

package(default_visibility = ["//visibility:public"])

cc_library(
name = "logs",
srcs = glob(["**/*.cc"]),
hdrs = glob(["**/*.h"]),
include_prefix = "src/logs",
deps = [
"//api",
"//sdk:headers",
],
)
3 changes: 3 additions & 0 deletions sdk/src/logs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_library(opentelemetry_logs logger_provider.cc logger.cc)

target_link_libraries(opentelemetry_logs opentelemetry_common)
Empty file removed sdk/src/logs/TBD
Empty file.
60 changes: 60 additions & 0 deletions sdk/src/logs/logger.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright The OpenTelemetry Authors
*
* 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.
*/

#include "opentelemetry/sdk/logs/logger.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace logs
{
Logger::Logger(std::shared_ptr<LoggerProvider> logger_provider) noexcept
: logger_provider_(logger_provider)
{}

void Logger::log(const opentelemetry::logs::LogRecord &record) noexcept
{
// If this logger does not have a processor, no need to create a log record
auto processor = logger_provider_.lock()->GetProcessor();
if (processor == nullptr)
{
return;
}

// TODO: Sampler logic (should include check for minSeverity)

/**
* Convert the LogRecord to the heap first before sending to processor.
* TODO: Change the API log(LogRecord) function to log(*LogRecord) so the following line
* converting record a heap variable can be removed
*/
auto record_pointer =
std::unique_ptr<opentelemetry::logs::LogRecord>(new opentelemetry::logs::LogRecord(record));

// TODO: Do not want to overwrite user-set timestamp if there already is one -
// add a flag in the API to check if timestamp is set by user already before setting timestamp

// Inject timestamp if none is set
record_pointer->timestamp = core::SystemTimestamp(std::chrono::system_clock::now());
// TODO: inject traceid/spanid later

// Send the log record to the processor
processor->OnReceive(std::move(record_pointer));
}

} // namespace logs
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
81 changes: 81 additions & 0 deletions sdk/src/logs/logger_provider.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright The OpenTelemetry Authors
*
* 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.
*/

#include "opentelemetry/sdk/logs/logger_provider.h"

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace logs
{

LoggerProvider::LoggerProvider() noexcept : processor_{nullptr} {}

opentelemetry::nostd::shared_ptr<opentelemetry::logs::Logger> LoggerProvider::GetLogger(
opentelemetry::nostd::string_view name,
opentelemetry::nostd::string_view options) noexcept
{
// Ensure only one thread can read/write from the map of loggers
std::lock_guard<std::mutex> lock_guard{mu_};

// If a logger with a name "name" already exists, return it
auto loggerkv = loggers_.find(name.data());
if (loggerkv != loggers_.end())
{
return opentelemetry::nostd::shared_ptr<opentelemetry::logs::Logger>(loggerkv->second);
}

// Check if creating a new logger would exceed the max number of loggers
// TODO: Remove the noexcept from the API's and SDK's GetLogger(~)
/*
if (loggers_.size() > MAX_LOGGER_COUNT)
{
#if __EXCEPTIONS
throw std::length_error("Number of loggers exceeds max count");
#else
std::terminate();
#endif
}
*/

// If no logger with that name exists yet, create it and add it to the map of loggers

opentelemetry::nostd::shared_ptr<opentelemetry::logs::Logger> logger(
new Logger(this->shared_from_this()));
loggers_[name.data()] = logger;
return logger;
}

opentelemetry::nostd::shared_ptr<opentelemetry::logs::Logger> LoggerProvider::GetLogger(
opentelemetry::nostd::string_view name,
nostd::span<nostd::string_view> args) noexcept
{
// Currently, no args support
return GetLogger(name);
}

std::shared_ptr<LogProcessor> LoggerProvider::GetProcessor() noexcept
{
return processor_.load();
}

void LoggerProvider::SetProcessor(std::shared_ptr<LogProcessor> processor) noexcept
{
processor_.store(processor);
}
} // namespace logs
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
1 change: 1 addition & 0 deletions sdk/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
add_subdirectory(common)
add_subdirectory(trace)
add_subdirectory(metrics)
add_subdirectory(logs)
Loading

0 comments on commit d33ffdb

Please sign in to comment.