Skip to content

Commit

Permalink
fd sink
Browse files Browse the repository at this point in the history
Signed-off-by: dentiny <[email protected]>
  • Loading branch information
dentiny committed Jan 30, 2025
1 parent 2f859d0 commit f6cbd36
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/ray/util/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,13 @@ ray_cc_library(
":util",
],
)

ray_cc_library(
name = "sodlog_fd_sink",
hdrs = ["spdlog_fd_sink.h"],
deps = [
":compat",
":util",
"@com_github_spdlog//:spdlog",
],
)
69 changes: 69 additions & 0 deletions src/ray/util/spdlog_fd_sink.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2025 The Ray 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 <spdlog/sinks/base_sink.h>

#include "ray/util/compat.h"
#include "ray/util/util.h"

#if defined(__APPLE__) || defined(__linux__)
#include <unistd.h>
#elif defined(_WIN32)
#include <windows.h>
#endif

namespace spdlog::sinks {

// A sink which logs to the file descriptor.
template <typename Mutex>
class fd_sink final : public base_sink<Mutex> {
public:
// [fd] is not owned by [FdSink], which means the file descriptor should be closed by
// caller.
explicit fd_sink(int fd) : fd_(fd) {}

protected:
void sink_it_(const details::log_msg &msg) override {
memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(msg, formatted);

#if defined(__APPLE__) || defined(__linux__)
RAY_CHECK_EQ(write(fd_, formatted.data(), formatted.size()), formatted.size())
<< "Fails to write because " << strerror(errno);
#elif defined(_WIN32)
LPDWORD bytes_written;
BOOL success =
WriteFile(fd_, formatted.data(), (DWORD)formatted.size(), &bytes_written, NULL);
RAY_CHECK(success);
RAY_CHECK_EQ((LPDWORD)formatted.size(), bytes_written);
#endif
}
void flush_() override {
#if defined(__APPLE__) || defined(__linux__)
RAY_CHECK_EQ(close(fd_), 0) << "Fails to close file because " << strerror(errno);
#elif defined(_WIN32)
RAY_CHECK(CloseHandle(fd_));
#endif
}

private:
MEMFD_TYPE_NON_UNIQUE fd_;
};

using fd_sink_mt = fd_sink<std::mutex>;
using fd_sink_st = fd_sink<details::null_mutex>;

} // namespace spdlog::sinks
11 changes: 11 additions & 0 deletions src/ray/util/tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,14 @@ ray_cc_test(
size = "small",
tags = ["team:core"],
)

ray_cc_test(
name = "spdlog_fd_sink_test",
srcs = ["spdlog_fd_sink_test.cc"],
deps = [
"//src/ray/util:sodlog_fd_sink",
"@com_google_googletest//:gtest_main",
],
size = "small",
tags = ["team:core"],
)
57 changes: 57 additions & 0 deletions src/ray/util/tests/spdlog_fd_sink_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2025 The Ray 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 "ray/util/spdlog_fd_sink.h"

#include <gtest/gtest.h>

namespace spdlog::sinks {

namespace {

#if defined(__APPLE__) || defined(__linux__)
int GetStdoutHandle() { return STDOUT_FILENO; }
#elif defined(_WIN32)
HANDLE GetStdoutHandle() { return GetStdHandle(STD_OUTPUT_HANDLE); }
#endif

// Returns "helloworld" for whatever message; here we don't care the what message is
// logged, we only care whether msg has been written to the given file descriptor
// correctly.
class NoopFormatter : public formatter {
public:
void format(const details::log_msg &msg, memory_buf_t &dest) override {
dest.append(std::string{"helloworld"});
}
std::unique_ptr<formatter> clone() const override {
return std::make_unique<NoopFormatter>();
}
};

TEST(SpdlogFdSinkTest, SinkWithFd) {
fd_sink_st sink{GetStdoutHandle()};
sink.set_formatter(std::make_unique<NoopFormatter>());
details::log_msg msg_to_log{
/*logger_name=*/"logger_name", level::level_enum::info, /*msg=*/"content"};

testing::internal::CaptureStdout();
sink.log(msg_to_log);
const std::string stdout_content = testing::internal::GetCapturedStdout();

EXPECT_EQ(stdout_content, "helloworld");
};

} // namespace

} // namespace spdlog::sinks

0 comments on commit f6cbd36

Please sign in to comment.