From 31437c36d4fd2d8db05685d5511e6f1588cac828 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 18 Feb 2025 11:02:17 -0500 Subject: [PATCH 01/86] initial commit of instance object --- src/viam/sdk/CMakeLists.txt | 2 ++ src/viam/sdk/common/instance.cpp | 11 +++++++++++ src/viam/sdk/common/instance.hpp | 24 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 src/viam/sdk/common/instance.cpp create mode 100644 src/viam/sdk/common/instance.hpp diff --git a/src/viam/sdk/CMakeLists.txt b/src/viam/sdk/CMakeLists.txt index cd7992f2a..e42db9ae5 100644 --- a/src/viam/sdk/CMakeLists.txt +++ b/src/viam/sdk/CMakeLists.txt @@ -50,6 +50,7 @@ target_sources(viamsdk PRIVATE common/client_helper.cpp common/exception.cpp + common/instance.cpp common/linear_algebra.cpp common/pose.cpp common/proto_value.cpp @@ -142,6 +143,7 @@ target_sources(viamsdk FILES ../../viam/sdk/common/client_helper.hpp ../../viam/sdk/common/exception.hpp + ../../viam/sdk/common/instance.hpp ../../viam/sdk/common/linear_algebra.hpp ../../viam/sdk/common/pose.hpp ../../viam/sdk/common/proto_convert.hpp diff --git a/src/viam/sdk/common/instance.cpp b/src/viam/sdk/common/instance.cpp new file mode 100644 index 000000000..1ec93d01f --- /dev/null +++ b/src/viam/sdk/common/instance.cpp @@ -0,0 +1,11 @@ +#include <viam/sdk/common/instance.hpp> + +namespace viam { +namespace sdk { + +Instance::Instance() { + registry_.initialize(); +} + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/common/instance.hpp b/src/viam/sdk/common/instance.hpp new file mode 100644 index 000000000..8297b74e4 --- /dev/null +++ b/src/viam/sdk/common/instance.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include <viam/sdk/registry/registry.hpp> + +namespace viam { +namespace sdk { + +/// @brief Instance management for Viam C++ SDK applications. +/// This is a single instance class which is responsible for global setup and teardown related to +/// the SDK. An Instance must be constructed before doing anything else in a program, and it must +/// remain alive in a valid state for the duration of the program. Creating multiple overlapping +/// Instance objects is an error. +class Instance { + public: + Instance(); + + Registry& registry(); + + private: + Registry registry_; +}; + +} // namespace sdk +} // namespace viam From 932ebaa1885b2e238cf339d0642c681ebf653b7a Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 18 Feb 2025 11:04:40 -0500 Subject: [PATCH 02/86] wip: initial commit to get sdk building with instance --- src/viam/sdk/module/service.cpp | 38 ++++++++++-------- src/viam/sdk/module/service.hpp | 7 +++- src/viam/sdk/registry/registry.cpp | 62 ++++++++++++++---------------- src/viam/sdk/registry/registry.hpp | 51 ++++++++++++------------ src/viam/sdk/robot/client.cpp | 27 +++++++------ src/viam/sdk/robot/client.hpp | 21 ++++++++-- src/viam/sdk/rpc/server.cpp | 5 +-- src/viam/sdk/rpc/server.hpp | 4 +- 8 files changed, 119 insertions(+), 96 deletions(-) diff --git a/src/viam/sdk/module/service.cpp b/src/viam/sdk/module/service.cpp index 53f1fe9bc..526beecb5 100644 --- a/src/viam/sdk/module/service.cpp +++ b/src/viam/sdk/module/service.cpp @@ -57,7 +57,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { std::shared_ptr<Resource> res; const Dependencies deps = parent.get_dependencies_(&request->dependencies(), cfg.name()); const std::shared_ptr<const ModelRegistration> reg = - Registry::lookup_model(cfg.api(), cfg.model()); + parent.registry_.lookup_model(cfg.api(), cfg.model()); if (reg) { try { res = reg->construct_resource(deps, cfg); @@ -111,7 +111,8 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { BOOST_LOG_TRIVIAL(error) << "unable to stop resource: " << err.what(); } - const std::shared_ptr<const ModelRegistration> reg = Registry::lookup_model(cfg.name()); + const std::shared_ptr<const ModelRegistration> reg = + parent.registry_.lookup_model(cfg.name()); if (reg) { try { const std::shared_ptr<Resource> res = reg->construct_resource(deps, cfg); @@ -131,7 +132,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { ResourceConfig cfg = from_proto(proto); const std::shared_ptr<const ModelRegistration> reg = - Registry::lookup_model(cfg.api(), cfg.model()); + parent.registry_.lookup_model(cfg.api(), cfg.model()); if (!reg) { return grpc::Status(grpc::UNKNOWN, "unable to validate resource " + cfg.resource_name().name() + @@ -207,31 +208,36 @@ Dependencies ModuleService::get_dependencies_( std::shared_ptr<Resource> ModuleService::get_parent_resource_(const Name& name) { if (!parent_) { - parent_ = RobotClient::at_local_socket(parent_addr_, {0, boost::none}); + parent_ = RobotClient::at_local_socket(parent_addr_, {0, boost::none}, registry_); } return parent_->resource_by_name(name); } -ModuleService::ModuleService(std::string addr) - : module_(std::make_unique<Module>(std::move(addr))), server_(std::make_unique<Server>()) { +ModuleService::ModuleService(std::string addr, Registry& registry) + : registry_(registry), + module_(std::make_unique<Module>(std::move(addr))), + server_(std::make_unique<Server>(®istry_)) { impl_ = std::make_unique<ServiceImpl>(*this); } ModuleService::ModuleService(int argc, char** argv, - const std::vector<std::shared_ptr<ModelRegistration>>& registrations) - : ModuleService([argc, argv] { - if (argc < 2) { - throw Exception(ErrorCondition::k_connection, - "Need socket path as command line argument"); - } - return argv[1]; - }()) { + const std::vector<std::shared_ptr<ModelRegistration>>& registrations, + Registry& registry) + : ModuleService( + [argc, argv] { + if (argc < 2) { + throw Exception(ErrorCondition::k_connection, + "Need socket path as command line argument"); + } + return argv[1]; + }(), + registry) { set_logger_severity_from_args(argc, argv); for (auto&& mr : registrations) { - Registry::register_model(mr); + registry_.register_model(mr); add_model_from_registry(mr->api(), mr->model()); } } @@ -274,7 +280,7 @@ void ModuleService::add_model_from_registry_inlock_(API api, Model model, const std::lock_guard<std::mutex>&) { const std::shared_ptr<const ResourceServerRegistration> creator = - Registry::lookup_resource_server(api); + registry_.lookup_resource_server(api); std::string name; if (creator && creator->service_descriptor()) { name = creator->service_descriptor()->full_name(); diff --git a/src/viam/sdk/module/service.hpp b/src/viam/sdk/module/service.hpp index 799ba1ab5..cffc47fe7 100644 --- a/src/viam/sdk/module/service.hpp +++ b/src/viam/sdk/module/service.hpp @@ -31,7 +31,7 @@ class ModuleService { public: /// @brief Creates a new ModuleService that can serve on the provided socket. /// @param addr Address of socket to serve on. - explicit ModuleService(std::string addr); + explicit ModuleService(std::string addr, Registry& registry); /// @brief Creates a new ModuleService. Socket path and log level will be /// inferred from passed in command line arguments, and passed in model @@ -41,7 +41,8 @@ class ModuleService { /// @param registrations Models to register and add to the module. explicit ModuleService(int argc, char** argv, - const std::vector<std::shared_ptr<ModelRegistration>>& registrations); + const std::vector<std::shared_ptr<ModelRegistration>>& registrations, + Registry& registry); ~ModuleService(); /// @brief Starts module. serve will return when SIGINT or SIGTERM is received @@ -64,6 +65,8 @@ class ModuleService { std::string const& resource_name); std::shared_ptr<Resource> get_parent_resource_(const Name& name); + Registry& registry_; + std::mutex lock_; std::unique_ptr<Module> module_; std::shared_ptr<RobotClient> parent_; diff --git a/src/viam/sdk/registry/registry.cpp b/src/viam/sdk/registry/registry.cpp index 57e857f00..71e3e7711 100644 --- a/src/viam/sdk/registry/registry.cpp +++ b/src/viam/sdk/registry/registry.cpp @@ -122,7 +122,7 @@ void Registry::register_resource_client_( } std::shared_ptr<const ModelRegistration> Registry::lookup_model_inlock_( - const std::string& name, const std::lock_guard<std::mutex>&) { + const std::string& name, const std::lock_guard<std::mutex>&) const { if (resources_.find(name) == resources_.end()) { return nullptr; } @@ -130,19 +130,20 @@ std::shared_ptr<const ModelRegistration> Registry::lookup_model_inlock_( return resources_.at(name); } -std::shared_ptr<const ModelRegistration> Registry::lookup_model(const std::string& name) { +std::shared_ptr<const ModelRegistration> Registry::lookup_model(const std::string& name) const { const std::lock_guard<std::mutex> lock(lock_); return lookup_model_inlock_(name, lock); } std::shared_ptr<const ModelRegistration> Registry::lookup_model(const API& api, - const Model& model) { + const Model& model) const { const std::lock_guard<std::mutex> lock(lock_); const std::string name = api.to_string() + "/" + model.to_string(); return lookup_model_inlock_(name, lock); } -std::shared_ptr<const ResourceServerRegistration> Registry::lookup_resource_server(const API& api) { +std::shared_ptr<const ResourceServerRegistration> Registry::lookup_resource_server( + const API& api) const { const std::lock_guard<std::mutex> lock(lock_); if (server_apis_.find(api) == server_apis_.end()) { return nullptr; @@ -151,7 +152,8 @@ std::shared_ptr<const ResourceServerRegistration> Registry::lookup_resource_serv return server_apis_.at(api); } -std::shared_ptr<const ResourceClientRegistration> Registry::lookup_resource_client(const API& api) { +std::shared_ptr<const ResourceClientRegistration> Registry::lookup_resource_client( + const API& api) const { const std::lock_guard<std::mutex> lock(lock_); if (client_apis_.find(api) == client_apis_.end()) { return nullptr; @@ -161,7 +163,7 @@ std::shared_ptr<const ResourceClientRegistration> Registry::lookup_resource_clie } const google::protobuf::ServiceDescriptor* Registry::get_service_descriptor_( - const char* service_full_name) { + const char* service_full_name) const { const google::protobuf::DescriptorPool* p = google::protobuf::DescriptorPool::generated_pool(); const google::protobuf::ServiceDescriptor* sd = p->FindServiceByName(service_full_name); if (!sd) { @@ -171,12 +173,12 @@ const google::protobuf::ServiceDescriptor* Registry::get_service_descriptor_( } const std::unordered_map<API, std::shared_ptr<const ResourceServerRegistration>>& -Registry::registered_resource_servers() { +Registry::registered_resource_servers() const { return server_apis_; } const std::unordered_map<std::string, std::shared_ptr<const ModelRegistration>>& -Registry::registered_models() { +Registry::registered_models() const { return resources_; } @@ -184,28 +186,28 @@ const google::protobuf::ServiceDescriptor* ResourceServerRegistration::service_d return service_descriptor_; } -void register_resources() { +void Registry::register_resources() { // Register all components - Registry::register_resource<impl::ArmClient, impl::ArmServer>(); - Registry::register_resource<impl::BaseClient, impl::BaseServer>(); - Registry::register_resource<impl::BoardClient, impl::BoardServer>(); - Registry::register_resource<impl::CameraClient, impl::CameraServer>(); - Registry::register_resource<impl::EncoderClient, impl::EncoderServer>(); - Registry::register_resource<impl::GantryClient, impl::GantryServer>(); - Registry::register_resource<impl::GenericComponentClient, impl::GenericComponentServer>(); - Registry::register_resource<impl::GripperClient, impl::GripperServer>(); - Registry::register_resource<impl::MotorClient, impl::MotorServer>(); - Registry::register_resource<impl::MovementSensorClient, impl::MovementSensorServer>(); - Registry::register_resource<impl::PoseTrackerClient, impl::PoseTrackerServer>(); - Registry::register_resource<impl::PowerSensorClient, impl::PowerSensorServer>(); - Registry::register_resource<impl::SensorClient, impl::SensorServer>(); - Registry::register_resource<impl::ServoClient, impl::ServoServer>(); + register_resource<impl::ArmClient, impl::ArmServer>(); + register_resource<impl::BaseClient, impl::BaseServer>(); + register_resource<impl::BoardClient, impl::BoardServer>(); + register_resource<impl::CameraClient, impl::CameraServer>(); + register_resource<impl::EncoderClient, impl::EncoderServer>(); + register_resource<impl::GantryClient, impl::GantryServer>(); + register_resource<impl::GenericComponentClient, impl::GenericComponentServer>(); + register_resource<impl::GripperClient, impl::GripperServer>(); + register_resource<impl::MotorClient, impl::MotorServer>(); + register_resource<impl::MovementSensorClient, impl::MovementSensorServer>(); + register_resource<impl::PoseTrackerClient, impl::PoseTrackerServer>(); + register_resource<impl::PowerSensorClient, impl::PowerSensorServer>(); + register_resource<impl::SensorClient, impl::SensorServer>(); + register_resource<impl::ServoClient, impl::ServoServer>(); // Register all services - Registry::register_resource<impl::GenericServiceClient, impl::GenericServiceServer>(); - Registry::register_resource<impl::MLModelServiceClient, impl::MLModelServiceServer>(); - Registry::register_resource<impl::MotionClient, impl::MotionServer>(); - Registry::register_resource<impl::NavigationClient, impl::NavigationServer>(); + register_resource<impl::GenericServiceClient, impl::GenericServiceServer>(); + register_resource<impl::MLModelServiceClient, impl::MLModelServiceServer>(); + register_resource<impl::MotionClient, impl::MotionServer>(); + register_resource<impl::NavigationClient, impl::NavigationServer>(); } void Registry::initialize() { @@ -220,11 +222,5 @@ void Registry::initialize() { grpc::reflection::InitProtoReflectionServerBuilderPlugin(); } -std::unordered_map<std::string, std::shared_ptr<const ModelRegistration>> Registry::resources_; -std::unordered_map<API, std::shared_ptr<const ResourceClientRegistration>> Registry::client_apis_; -std::unordered_map<API, std::shared_ptr<const ResourceServerRegistration>> Registry::server_apis_; -std::mutex Registry::lock_; -bool Registry::initialized_{false}; - } // namespace sdk } // namespace viam diff --git a/src/viam/sdk/registry/registry.hpp b/src/viam/sdk/registry/registry.hpp index b00d98833..4431575d6 100644 --- a/src/viam/sdk/registry/registry.hpp +++ b/src/viam/sdk/registry/registry.hpp @@ -106,23 +106,22 @@ class Registry { /// @brief Registers a resource with the Registry. /// @param resource An object containing resource registration information. /// @throws `Exception` if the resource has already been registered. - static void register_model(std::shared_ptr<const ModelRegistration> resource); + void register_model(std::shared_ptr<const ModelRegistration> resource); /// @brief Lookup a given registered resource. /// @param name The name of the resource to lookup. /// @return a `shared_ptr` to the resource's registration data. - static std::shared_ptr<const ModelRegistration> lookup_model(const std::string& name); + std::shared_ptr<const ModelRegistration> lookup_model(const std::string& name) const; /// @brief Lookup a given registered resource. /// @param api The api of the resource to lookup. /// @param model The model of the resource to lookup. /// @return a `shared_ptr` to the resource's registration data. - static std::shared_ptr<const ModelRegistration> lookup_model(const API& api, - const Model& model); + std::shared_ptr<const ModelRegistration> lookup_model(const API& api, const Model& model) const; /// @brief Register a resource client constructor template <typename ResourceClientT> - static void register_resource_client() { + void register_resource_client() { class ResourceClientRegistration2 final : public ResourceClientRegistration { public: using ResourceClientRegistration::ResourceClientRegistration; @@ -139,7 +138,7 @@ class Registry { /// @brief Register a resource server constructor. template <typename ResourceServerT> - static void register_resource_server() { + void register_resource_server() { class ResourceServerRegistration2 final : public ResourceServerRegistration { public: using ResourceServerRegistration::ResourceServerRegistration; @@ -159,7 +158,7 @@ class Registry { /// @brief Register resource client and server constructors template <typename ResourceClientT, typename ResourceServerT> - static void register_resource() { + void register_resource() { register_resource_client<ResourceClientT>(); register_resource_server<ResourceServerT>(); } @@ -167,44 +166,46 @@ class Registry { /// @brief Lookup a registered server api. /// @param api The api to lookup. /// @return A `shared_ptr` to the registered api's `ResourceServerRegistration`. - static std::shared_ptr<const ResourceServerRegistration> lookup_resource_server(const API& api); + std::shared_ptr<const ResourceServerRegistration> lookup_resource_server(const API& api) const; /// @brief Lookup a registered client api. /// @param api The api to lookup. /// @return A `shared_ptr` to the registered api's `ResourceClientRegistration`. - static std::shared_ptr<const ResourceClientRegistration> lookup_resource_client(const API& api); + std::shared_ptr<const ResourceClientRegistration> lookup_resource_client(const API& api) const; /// @brief Provide information on registered resource models. /// @return A map from name to `ModelRegistration` of all registered resource models. - static const std::unordered_map<std::string, std::shared_ptr<const ModelRegistration>>& - registered_models(); + const std::unordered_map<std::string, std::shared_ptr<const ModelRegistration>>& + registered_models() const; /// @brief Provide access to registered resources. /// @return A map from `API` to `ResourceServerRegistration` of all registered resources. - static const std::unordered_map<API, std::shared_ptr<const ResourceServerRegistration>>& - registered_resource_servers(); + const std::unordered_map<API, std::shared_ptr<const ResourceServerRegistration>>& + registered_resource_servers() const; /// @brief Initialized the Viam registry. No-op if it has already been called. - static void initialize(); + void initialize(); private: - static std::mutex lock_; - static bool initialized_; - static std::unordered_map<std::string, std::shared_ptr<const ModelRegistration>> resources_; - static std::unordered_map<API, std::shared_ptr<const ResourceClientRegistration>> client_apis_; - static std::unordered_map<API, std::shared_ptr<const ResourceServerRegistration>> server_apis_; + mutable std::mutex lock_; + bool initialized_{false}; + std::unordered_map<std::string, std::shared_ptr<const ModelRegistration>> resources_; + std::unordered_map<API, std::shared_ptr<const ResourceClientRegistration>> client_apis_; + std::unordered_map<API, std::shared_ptr<const ResourceServerRegistration>> server_apis_; - static void register_resource_server_( + void register_resources(); + + void register_resource_server_( API api, std::shared_ptr<ResourceServerRegistration> resource_registration); - static void register_resource_client_( + void register_resource_client_( API api, std::shared_ptr<ResourceClientRegistration> resource_registration); - static const google::protobuf::ServiceDescriptor* get_service_descriptor_( - const char* service_full_name); + const google::protobuf::ServiceDescriptor* get_service_descriptor_( + const char* service_full_name) const; - static std::shared_ptr<const ModelRegistration> lookup_model_inlock_( - const std::string& name, const std::lock_guard<std::mutex>&); + std::shared_ptr<const ModelRegistration> lookup_model_inlock_( + const std::string& name, const std::lock_guard<std::mutex>&) const; }; } // namespace sdk diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index fff691fd2..6ac049eba 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -178,7 +178,7 @@ void RobotClient::refresh() { // are being properly registered from name.subtype(), or update what we're // using for lookup const std::shared_ptr<const ResourceClientRegistration> rs = - Registry::lookup_resource_client({name.namespace_(), name.type(), name.subtype()}); + registry_.lookup_resource_client({name.namespace_(), name.type(), name.subtype()}); if (rs) { try { const std::shared_ptr<Resource> rpc_client = @@ -221,13 +221,12 @@ void RobotClient::refresh_every() { } }; -RobotClient::RobotClient(std::shared_ptr<ViamChannel> channel) - : channel_(channel->channel()), +RobotClient::RobotClient(std::shared_ptr<ViamChannel> channel, Registry& registry) + : registry_(registry), + channel_(channel->channel()), viam_channel_(std::move(channel)), should_close_channel_(false), - impl_(std::make_unique<impl>(RobotService::NewStub(channel_))) { - Registry::initialize(); -} + impl_(std::make_unique<impl>(RobotService::NewStub(channel_))) {} std::vector<Name> RobotClient::resource_names() const { const std::lock_guard<std::mutex> lock(lock_); @@ -235,8 +234,10 @@ std::vector<Name> RobotClient::resource_names() const { } std::shared_ptr<RobotClient> RobotClient::with_channel(std::shared_ptr<ViamChannel> channel, - const Options& options) { - std::shared_ptr<RobotClient> robot = std::make_shared<RobotClient>(std::move(channel)); + const Options& options, + Registry& registry) { + std::shared_ptr<RobotClient> robot = + std::make_shared<RobotClient>(std::move(channel), registry); robot->refresh_interval_ = options.refresh_interval(); robot->should_refresh_ = (robot->refresh_interval_ > 0); if (robot->should_refresh_) { @@ -254,23 +255,25 @@ std::shared_ptr<RobotClient> RobotClient::with_channel(std::shared_ptr<ViamChann }; std::shared_ptr<RobotClient> RobotClient::at_address(const std::string& address, - const Options& options) { + const Options& options, + Registry& registry) { const char* uri = address.c_str(); auto channel = ViamChannel::dial(uri, options.dial_options()); - std::shared_ptr<RobotClient> robot = RobotClient::with_channel(channel, options); + std::shared_ptr<RobotClient> robot = RobotClient::with_channel(channel, options, registry); robot->should_close_channel_ = true; return robot; }; std::shared_ptr<RobotClient> RobotClient::at_local_socket(const std::string& address, - const Options& options) { + const Options& options, + Registry& registry) { const std::string addr = "unix://" + address; const char* uri = addr.c_str(); const std::shared_ptr<grpc::Channel> channel = sdk::impl::create_viam_channel(uri, grpc::InsecureChannelCredentials()); auto viam_channel = std::make_shared<ViamChannel>(channel, address.c_str(), nullptr); - std::shared_ptr<RobotClient> robot = RobotClient::with_channel(viam_channel, options); + std::shared_ptr<RobotClient> robot = RobotClient::with_channel(viam_channel, options, registry); robot->should_close_channel_ = true; return robot; diff --git a/src/viam/sdk/robot/client.hpp b/src/viam/sdk/robot/client.hpp index 9d63bd14b..09834e1d8 100644 --- a/src/viam/sdk/robot/client.hpp +++ b/src/viam/sdk/robot/client.hpp @@ -68,7 +68,8 @@ class RobotClient { /// @param address The address of the robot (IP address, URI, URL, etc.) /// @param options Options for connecting and refreshing. static std::shared_ptr<RobotClient> at_address(const std::string& address, - const Options& options); + const Options& options, + Registry& registry); /// @brief Creates a robot client connected to the robot at the provided local socket. /// @param address The local socket of the robot (a .sock file, etc.). @@ -76,7 +77,8 @@ class RobotClient { /// Creates a direct connection to the robot using the `unix://` scheme. /// Only useful for connecting to robots across Unix sockets. static std::shared_ptr<RobotClient> at_local_socket(const std::string& address, - const Options& options); + const Options& options, + Registry& registry); /// @brief Creates a robot client connected to the provided channel. /// @param channel The channel to connect with. @@ -84,8 +86,11 @@ class RobotClient { /// Connects directly to a pre-existing channel. A robot created this way must be /// `close()`d manually. static std::shared_ptr<RobotClient> with_channel(std::shared_ptr<ViamChannel> channel, - const Options& options); - RobotClient(std::shared_ptr<ViamChannel> channel); + const Options& options, + Registry& registry); + + RobotClient(std::shared_ptr<ViamChannel> channel, Registry& registry); + std::vector<Name> resource_names() const; /// @brief Lookup and return a `shared_ptr` to a resource. @@ -147,17 +152,25 @@ class RobotClient { status get_machine_status() const; private: + Registry& registry_; + std::vector<std::shared_ptr<std::thread>> threads_; + std::atomic<bool> should_refresh_; unsigned int refresh_interval_; + std::shared_ptr<GrpcChannel> channel_; std::shared_ptr<ViamChannel> viam_channel_; bool should_close_channel_; + struct impl; std::unique_ptr<impl> impl_; + mutable std::mutex lock_; + std::vector<Name> resource_names_; ResourceManager resource_manager_; + void refresh_every(); }; diff --git a/src/viam/sdk/rpc/server.cpp b/src/viam/sdk/rpc/server.cpp index 408f23bf6..b2c46c695 100644 --- a/src/viam/sdk/rpc/server.cpp +++ b/src/viam/sdk/rpc/server.cpp @@ -15,12 +15,11 @@ namespace viam { namespace sdk { -Server::Server() : builder_(std::make_unique<grpc::ServerBuilder>()) { +Server::Server(const Registry* registry) : builder_(std::make_unique<grpc::ServerBuilder>()) { builder_->SetMaxReceiveMessageSize(kMaxMessageSize); builder_->SetMaxSendMessageSize(kMaxMessageSize); builder_->SetMaxMessageSize(kMaxMessageSize); - Registry::initialize(); - for (const auto& rr : Registry::registered_resource_servers()) { + for (const auto& rr : registry->registered_resource_servers()) { auto new_manager = std::make_shared<ResourceManager>(); auto server = rr.second->create_resource_server(new_manager, *this); managed_servers_.emplace(rr.first, std::move(server)); diff --git a/src/viam/sdk/rpc/server.hpp b/src/viam/sdk/rpc/server.hpp index e735a6351..5f868b779 100644 --- a/src/viam/sdk/rpc/server.hpp +++ b/src/viam/sdk/rpc/server.hpp @@ -23,11 +23,13 @@ class TestServer; namespace sdk { +class Registry; + /// @class Server server.hpp "rpc/server.hpp" /// @brief Defines gRPC `Server` functionality. class Server { public: - Server(); + Server(const Registry* registry); ~Server(); /// @brief Starts the grpc server. Can only be called once. From 04d0158412c31836d226576668c90ce36234d4f0 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 18 Feb 2025 14:14:58 -0500 Subject: [PATCH 03/86] add missing implementation --- src/viam/sdk/common/instance.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/viam/sdk/common/instance.cpp b/src/viam/sdk/common/instance.cpp index 1ec93d01f..3c277273d 100644 --- a/src/viam/sdk/common/instance.cpp +++ b/src/viam/sdk/common/instance.cpp @@ -7,5 +7,9 @@ Instance::Instance() { registry_.initialize(); } +Registry& Instance::registry() { + return registry_; +} + } // namespace sdk } // namespace viam From a105cef7426252039a7917153e0a34d3afc0a5a2 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 18 Feb 2025 14:15:56 -0500 Subject: [PATCH 04/86] update examples to use instance --- src/viam/examples/modules/simple/client.cpp | 5 ++++- src/viam/examples/modules/simple/main.cpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/viam/examples/modules/simple/client.cpp b/src/viam/examples/modules/simple/client.cpp index fcaab5eff..ac014d1e7 100644 --- a/src/viam/examples/modules/simple/client.cpp +++ b/src/viam/examples/modules/simple/client.cpp @@ -2,6 +2,7 @@ #include <memory> #include <string> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/components/sensor.hpp> #include <viam/sdk/robot/client.hpp> @@ -10,6 +11,8 @@ using namespace viam::sdk; int main() { + Instance inst; + const char* uri = "http://localhost:8080/"; // replace with your URI if connecting securely DialOptions dial_options; dial_options.set_allow_insecure_downgrade(true); // set to false if connecting securely @@ -24,7 +27,7 @@ int main() { std::string address(uri); Options options(1, opts); - std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options); + std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options, inst.registry()); // Print resources std::cout << "Resources\n"; diff --git a/src/viam/examples/modules/simple/main.cpp b/src/viam/examples/modules/simple/main.cpp index cfd783f66..b899d3b44 100644 --- a/src/viam/examples/modules/simple/main.cpp +++ b/src/viam/examples/modules/simple/main.cpp @@ -3,6 +3,7 @@ #include <sstream> #include <viam/sdk/common/exception.hpp> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/components/sensor.hpp> #include <viam/sdk/config/resource.hpp> @@ -75,6 +76,8 @@ ProtoStruct MySensor::get_readings(const ProtoStruct&) { } int main(int argc, char** argv) try { + Instance inst; + Model mysensor_model("viam", "sensor", "mysensor"); std::shared_ptr<ModelRegistration> mr = std::make_shared<ModelRegistration>( @@ -84,7 +87,7 @@ int main(int argc, char** argv) try { &MySensor::validate); std::vector<std::shared_ptr<ModelRegistration>> mrs = {mr}; - auto my_mod = std::make_shared<ModuleService>(argc, argv, mrs); + auto my_mod = std::make_shared<ModuleService>(argc, argv, mrs, inst.registry()); my_mod->serve(); return EXIT_SUCCESS; From 403f31610d1b95a705b466fad0b0873934acec0c Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 18 Feb 2025 16:21:21 -0500 Subject: [PATCH 05/86] only instance can construct registry --- src/viam/sdk/registry/registry.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/viam/sdk/registry/registry.hpp b/src/viam/sdk/registry/registry.hpp index 4431575d6..a98e05c6e 100644 --- a/src/viam/sdk/registry/registry.hpp +++ b/src/viam/sdk/registry/registry.hpp @@ -187,6 +187,10 @@ class Registry { void initialize(); private: + friend class Instance; + + Registry() = default; + mutable std::mutex lock_; bool initialized_{false}; std::unordered_map<std::string, std::shared_ptr<const ModelRegistration>> resources_; From 27eeb1331c28810243859a7c5f0f5606a4e69ba6 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 21 Feb 2025 12:55:42 -0500 Subject: [PATCH 06/86] make tests work with registry member approach --- src/viam/sdk/registry/registry.hpp | 6 +++--- src/viam/sdk/tests/mocks/mock_robot.cpp | 2 +- src/viam/sdk/tests/test_robot.cpp | 19 +++++++++++-------- src/viam/sdk/tests/test_utils.hpp | 17 +++++++++++++++-- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/viam/sdk/registry/registry.hpp b/src/viam/sdk/registry/registry.hpp index a98e05c6e..75e2324e3 100644 --- a/src/viam/sdk/registry/registry.hpp +++ b/src/viam/sdk/registry/registry.hpp @@ -183,14 +183,14 @@ class Registry { const std::unordered_map<API, std::shared_ptr<const ResourceServerRegistration>>& registered_resource_servers() const; - /// @brief Initialized the Viam registry. No-op if it has already been called. - void initialize(); - private: friend class Instance; Registry() = default; + /// @brief Initialized the Viam registry. No-op if it has already been called. + void initialize(); + mutable std::mutex lock_; bool initialized_{false}; std::unordered_map<std::string, std::shared_ptr<const ModelRegistration>> resources_; diff --git a/src/viam/sdk/tests/mocks/mock_robot.cpp b/src/viam/sdk/tests/mocks/mock_robot.cpp index cdef0fe78..8e28b944b 100644 --- a/src/viam/sdk/tests/mocks/mock_robot.cpp +++ b/src/viam/sdk/tests/mocks/mock_robot.cpp @@ -26,7 +26,7 @@ std::vector<Name> registered_models_for_resource(const std::shared_ptr<Resource> std::string resource_type; std::string resource_subtype; std::vector<Name> resource_names; - for (const auto& kv : Registry::registered_models()) { + for (const auto& kv : GlobalInstance::registry().registered_models()) { const std::shared_ptr<const ModelRegistration> reg = kv.second; if (reg->api() == resource->api()) { resource_type = reg->api().resource_type(); diff --git a/src/viam/sdk/tests/test_robot.cpp b/src/viam/sdk/tests/test_robot.cpp index 9f1093d49..e7ccc0de1 100644 --- a/src/viam/sdk/tests/test_robot.cpp +++ b/src/viam/sdk/tests/test_robot.cpp @@ -42,7 +42,7 @@ void robot_client_to_mocks_pipeline(F&& test_case) { rm->add(std::string("mock_generic"), generic::MockGenericComponent::get_mock_generic()); rm->add(std::string("mock_motor"), motor::MockMotor::get_mock_motor()); rm->add(std::string("mock_camera"), camera::MockCamera::get_mock_camera()); - auto server = std::make_shared<sdk::Server>(); + auto server = std::make_shared<sdk::Server>(&GlobalInstance::registry()); MockRobotService service(rm, *server); server->start(); @@ -51,7 +51,8 @@ void robot_client_to_mocks_pipeline(F&& test_case) { auto test_server = TestServer(server); auto grpc_channel = test_server.grpc_in_process_channel(); auto viam_channel = std::make_shared<ViamChannel>(grpc_channel, "", nullptr); - auto client = RobotClient::with_channel(viam_channel, Options(0, boost::none)); + auto client = RobotClient::with_channel( + viam_channel, Options(0, boost::none), GlobalInstance::registry()); // Run the passed-in test case on the created stack and give access to the // created RobotClient and MockRobotService. @@ -62,6 +63,8 @@ void robot_client_to_mocks_pipeline(F&& test_case) { } BOOST_AUTO_TEST_CASE(test_registering_resources) { + auto& registry = GlobalInstance::registry(); + // To test with mock resources we need to be able to create them, which means registering // constructors. This tests that we register correctly. Model camera_model("fake", "fake", "mock_camera"); @@ -70,7 +73,7 @@ BOOST_AUTO_TEST_CASE(test_registering_resources) { camera_model, [](Dependencies, ResourceConfig cfg) { return camera::MockCamera::get_mock_camera(); }, [](ResourceConfig cfg) -> std::vector<std::string> { return {}; }); - Registry::register_model(cr); + registry.register_model(cr); Model generic_model("fake", "fake", "mock_generic"); std::shared_ptr<ModelRegistration> gr = std::make_shared<ModelRegistration>( @@ -80,7 +83,7 @@ BOOST_AUTO_TEST_CASE(test_registering_resources) { return generic::MockGenericComponent::get_mock_generic(); }, [](ResourceConfig cfg) -> std::vector<std::string> { return {}; }); - Registry::register_model(gr); + registry.register_model(gr); Model motor_model("fake", "fake", "mock_motor"); std::shared_ptr<ModelRegistration> mr = std::make_shared<ModelRegistration>( @@ -88,11 +91,11 @@ BOOST_AUTO_TEST_CASE(test_registering_resources) { motor_model, [](Dependencies, ResourceConfig cfg) { return motor::MockMotor::get_mock_motor(); }, [](ResourceConfig cfg) -> std::vector<std::string> { return {}; }); - Registry::register_model(mr); + registry.register_model(mr); - BOOST_CHECK(Registry::lookup_model(API::get<Camera>(), camera_model)); - BOOST_CHECK(Registry::lookup_model(API::get<GenericComponent>(), generic_model)); - BOOST_CHECK(Registry::lookup_model(API::get<Motor>(), motor_model)); + BOOST_CHECK(registry.lookup_model(API::get<Camera>(), camera_model)); + BOOST_CHECK(registry.lookup_model(API::get<GenericComponent>(), generic_model)); + BOOST_CHECK(registry.lookup_model(API::get<Motor>(), motor_model)); } BOOST_AUTO_TEST_CASE(test_resource_names) { diff --git a/src/viam/sdk/tests/test_utils.hpp b/src/viam/sdk/tests/test_utils.hpp index 400bc54a2..c24bed482 100644 --- a/src/viam/sdk/tests/test_utils.hpp +++ b/src/viam/sdk/tests/test_utils.hpp @@ -2,6 +2,7 @@ #include <grpcpp/grpcpp.h> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/config/resource.hpp> #include <viam/sdk/registry/registry.hpp> #include <viam/sdk/resource/resource.hpp> @@ -10,6 +11,17 @@ namespace viam { namespace sdktests { +struct GlobalInstance { + static sdk::Instance& get() { + static sdk::Instance inst; + return inst; + } + + static sdk::Registry& registry() { + return get().registry(); + } +}; + using namespace viam::sdk; ProtoStruct fake_map(); @@ -49,7 +61,7 @@ class TestServer { // The passed in test_case function will have access to the created ResourceClient. template <typename ResourceType, typename F> void client_to_mock_pipeline(std::shared_ptr<Resource> mock, F&& test_case) { - auto server = std::make_shared<sdk::Server>(); + auto server = std::make_shared<sdk::Server>(&GlobalInstance::registry()); // normally the high level server service (either robot or module) handles adding managed // resources, but in this case we must do it ourselves. @@ -61,7 +73,8 @@ void client_to_mock_pipeline(std::shared_ptr<Resource> mock, F&& test_case) { auto test_server = TestServer(server); auto grpc_channel = test_server.grpc_in_process_channel(); - auto resource_client = Registry::lookup_resource_client(API::get<ResourceType>()) + auto resource_client = GlobalInstance::registry() + .lookup_resource_client(API::get<ResourceType>()) ->create_rpc_client(mock->name(), std::move(grpc_channel)); // Run the passed-in test case on the created stack and give access to the From ce2aa8c54852cb2e88ff53dbc831331dd0081e02 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 24 Feb 2025 16:17:18 -0500 Subject: [PATCH 07/86] pimpl registry and update examples --- src/viam/examples/camera/example_camera.cpp | 8 +++++++- src/viam/examples/dial/example_dial.cpp | 7 ++++++- .../dial_api_key/example_dial_api_key.cpp | 7 ++++++- .../example_audio_classification_client.cpp | 9 +++++++-- src/viam/examples/modules/complex/client.cpp | 11 ++++++++--- src/viam/examples/modules/complex/main.cpp | 11 ++++++++--- .../modules/complex/test_complex_module.cpp | 5 +++-- src/viam/examples/motor/example_motor.cpp | 8 +++++++- src/viam/sdk/common/instance.cpp | 16 ++++++++++++---- src/viam/sdk/common/instance.hpp | 10 +++++++--- src/viam/sdk/module/service.cpp | 16 ++++++++-------- src/viam/sdk/module/service.hpp | 6 +++--- src/viam/sdk/registry/registry.hpp | 1 - src/viam/sdk/robot/client.cpp | 10 +++++----- src/viam/sdk/robot/client.hpp | 14 ++++++++------ src/viam/sdk/tests/mocks/mock_robot.cpp | 2 +- src/viam/sdk/tests/test_robot.cpp | 4 ++-- src/viam/sdk/tests/test_utils.hpp | 6 +++--- 18 files changed, 101 insertions(+), 50 deletions(-) diff --git a/src/viam/examples/camera/example_camera.cpp b/src/viam/examples/camera/example_camera.cpp index bc1b0ab9a..b0202a27e 100644 --- a/src/viam/examples/camera/example_camera.cpp +++ b/src/viam/examples/camera/example_camera.cpp @@ -3,6 +3,7 @@ #include <unistd.h> #include <vector> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/camera.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -13,6 +14,11 @@ int main() { using std::endl; namespace vs = ::viam::sdk; try { + // Every Viam C++ SDK program must have one and only one Instance object which is created + // before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + vs::Instance inst; + // If you want to connect to a remote robot, this should be the url of the robot // Ex: xxx.xxx.viam.cloud std::string robot_address("localhost:8080"); @@ -35,7 +41,7 @@ int main() { std::shared_ptr<vs::RobotClient> robot; try { - robot = vs::RobotClient::at_address(robot_address, options); + robot = vs::RobotClient::at_address(robot_address, options, inst.registry()); cout << "Successfully connected to the robot" << endl; } catch (const std::exception& e) { cerr << "Failed to connect to the robot. Exiting." << endl; diff --git a/src/viam/examples/dial/example_dial.cpp b/src/viam/examples/dial/example_dial.cpp index efa783dfb..28ccd7659 100644 --- a/src/viam/examples/dial/example_dial.cpp +++ b/src/viam/examples/dial/example_dial.cpp @@ -9,6 +9,7 @@ #include <boost/optional.hpp> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/generic.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -16,6 +17,10 @@ using namespace viam::sdk; int main() { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + Instance inst; + const char* uri = "<your robot URI here>"; DialOptions dial_options; std::string type = "<your authentication type>"; @@ -27,7 +32,7 @@ int main() { Options options(1, opts); // connect to robot, ensure we can refresh it - std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options); + std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options, inst.registry()); // ensure we can query resources std::vector<Name> resource_names = robot->resource_names(); diff --git a/src/viam/examples/dial_api_key/example_dial_api_key.cpp b/src/viam/examples/dial_api_key/example_dial_api_key.cpp index 4c47beffe..7c9e82fef 100644 --- a/src/viam/examples/dial_api_key/example_dial_api_key.cpp +++ b/src/viam/examples/dial_api_key/example_dial_api_key.cpp @@ -10,6 +10,7 @@ #include <boost/optional.hpp> #include <boost/program_options.hpp> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -18,6 +19,10 @@ using namespace viam::sdk; namespace po = boost::program_options; int main(int argc, char* argv[]) { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + Instance inst; + po::options_description desc("Allowed options"); desc.add_options()("help", "List options and exit")( "uri", po::value<std::string>(), "URI of robot")( @@ -41,7 +46,7 @@ int main(int argc, char* argv[]) { // connect to robot, ensure we can refresh it std::shared_ptr<RobotClient> robot = - RobotClient::at_address(vm["uri"].as<std::string>(), options); + RobotClient::at_address(vm["uri"].as<std::string>(), options, inst.registry()); // ensure we can query resources std::vector<Name> resource_names = robot->resource_names(); diff --git a/src/viam/examples/mlmodel/example_audio_classification_client.cpp b/src/viam/examples/mlmodel/example_audio_classification_client.cpp index 95e26f57c..ab06a082e 100644 --- a/src/viam/examples/mlmodel/example_audio_classification_client.cpp +++ b/src/viam/examples/mlmodel/example_audio_classification_client.cpp @@ -29,6 +29,7 @@ #include <boost/program_options.hpp> #include <boost/variant/get.hpp> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/services/mlmodel.hpp> @@ -78,6 +79,10 @@ constexpr char kRobotConfigTemplate[] = R"( } // namespace int main(int argc, char* argv[]) try { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + viam::sdk::Instance inst; + // Build up our command line options. The example operates in two // modes. In the "--generate" mode, it takes command line // parameters needed to satisfy the interpolation points in the @@ -234,8 +239,8 @@ int main(int argc, char* argv[]) try { dial_options.set_entity(opt_api_key_id.get()); dial_options.set_credentials(viam::sdk::Credentials("api-key", opt_api_key.get())); - auto robot = - vsdk::RobotClient::at_address(opt_robot_host.get(), {0, {std::move(dial_options)}}); + auto robot = vsdk::RobotClient::at_address( + opt_robot_host.get(), {0, {std::move(dial_options)}}, inst.registry()); // Obtain a handle to the MLModelService module on the robot. Note that the string // `yamnet_classification_tflite` is arbitrary. It just matches what was used to name the diff --git a/src/viam/examples/modules/complex/client.cpp b/src/viam/examples/modules/complex/client.cpp index ed321abd5..ea3444844 100644 --- a/src/viam/examples/modules/complex/client.cpp +++ b/src/viam/examples/modules/complex/client.cpp @@ -11,6 +11,7 @@ #include <grpcpp/grpcpp.h> #include <grpcpp/support/status.h> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/motor.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -21,6 +22,10 @@ using namespace viam::sdk; int main() { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + Instance inst; + const char* uri = "http://localhost:8080/"; // replace with your URI if connecting securely DialOptions dial_options; dial_options.set_allow_insecure_downgrade(true); // set to false if connecting securely @@ -37,11 +42,11 @@ int main() { // Register custom gizmo and summation clients so robot client can access resources // of that type from the server. - Registry::register_resource_client<GizmoClient>(); - Registry::register_resource_client<SummationClient>(); + inst.registry()->register_resource_client<GizmoClient>(); + inst.registry()->register_resource_client<SummationClient>(); // Connect to robot. - std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options); + std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options, inst.registry()); // Print resources. std::cout << "Resources" << std::endl; std::vector<Name> resource_names = robot->resource_names(); diff --git a/src/viam/examples/modules/complex/main.cpp b/src/viam/examples/modules/complex/main.cpp index 59f590733..5d3f85f67 100644 --- a/src/viam/examples/modules/complex/main.cpp +++ b/src/viam/examples/modules/complex/main.cpp @@ -5,6 +5,7 @@ #include <grpcpp/grpcpp.h> #include <grpcpp/server_context.h> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/base.hpp> #include <viam/sdk/components/component.hpp> #include <viam/sdk/config/resource.hpp> @@ -24,11 +25,15 @@ using namespace viam::sdk; int main(int argc, char** argv) { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + Instance inst; + Model mybase_model("viam", "base", "mybase"); // Make sure to explicity register resources with custom APIs. - Registry::register_resource_server<GizmoServer>(); - Registry::register_resource_server<SummationServer>(); + inst.registry()->register_resource_server<GizmoServer>(); + inst.registry()->register_resource_server<SummationServer>(); std::shared_ptr<ModelRegistration> mybase_mr = std::make_shared<ModelRegistration>( API::get<Base>(), @@ -51,7 +56,7 @@ int main(int argc, char** argv) { }); std::vector<std::shared_ptr<ModelRegistration>> mrs = {mybase_mr, mygizmo_mr, mysummation_mr}; - auto my_mod = std::make_shared<ModuleService>(argc, argv, mrs); + auto my_mod = std::make_shared<ModuleService>(argc, argv, mrs, inst.registry()); my_mod->serve(); return EXIT_SUCCESS; diff --git a/src/viam/examples/modules/complex/test_complex_module.cpp b/src/viam/examples/modules/complex/test_complex_module.cpp index 4984df8f0..228ef96c7 100644 --- a/src/viam/examples/modules/complex/test_complex_module.cpp +++ b/src/viam/examples/modules/complex/test_complex_module.cpp @@ -24,8 +24,9 @@ using namespace viam::sdktests; struct RegisterGizmoAndSummationFixture { RegisterGizmoAndSummationFixture() { - Registry::register_resource<GizmoClient, GizmoServer>(); - Registry::register_resource<SummationClient, SummationServer>(); + auto* registry = GlobalInstance::registry(); + registry->register_resource<GizmoClient, GizmoServer>(); + registry->register_resource<SummationClient, SummationServer>(); } // Test teardown is a noop; diff --git a/src/viam/examples/motor/example_motor.cpp b/src/viam/examples/motor/example_motor.cpp index c4d8023d5..1a5ff50b7 100644 --- a/src/viam/examples/motor/example_motor.cpp +++ b/src/viam/examples/motor/example_motor.cpp @@ -6,6 +6,7 @@ #include <string> #include <vector> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/motor.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -27,6 +28,11 @@ int main() { namespace vs = ::viam::sdk; try { + // Every Viam C++ SDK program must have one and only one Instance object which is created + // before any other C++ SDK objects and stays alive until all Viam C++ SDK objects are + // destroyed. + vs::Instance inst; + // If you want to connect to a remote robot, this should be the url of the robot // Ex: xxx.xxx.viam.cloud std::string robot_address("localhost:8080"); @@ -49,7 +55,7 @@ int main() { std::shared_ptr<vs::RobotClient> robot; try { - robot = vs::RobotClient::at_address(robot_address, options); + robot = vs::RobotClient::at_address(robot_address, options, inst.registry()); cout << "Successfully connected to the robot" << endl; } catch (const std::exception& e) { cerr << "Failed to connect to the robot. Exiting." << endl; diff --git a/src/viam/sdk/common/instance.cpp b/src/viam/sdk/common/instance.cpp index 3c277273d..c356aee54 100644 --- a/src/viam/sdk/common/instance.cpp +++ b/src/viam/sdk/common/instance.cpp @@ -1,14 +1,22 @@ #include <viam/sdk/common/instance.hpp> +#include <viam/sdk/registry/registry.hpp> + namespace viam { namespace sdk { -Instance::Instance() { - registry_.initialize(); +struct Instance::Impl { + Registry registry; +}; + +Instance::Instance() : impl_(std::make_unique<Instance::Impl>()) { + impl_->registry.initialize(); } -Registry& Instance::registry() { - return registry_; +Instance::~Instance() = default; + +Registry* Instance::registry() { + return &(impl_->registry); } } // namespace sdk diff --git a/src/viam/sdk/common/instance.hpp b/src/viam/sdk/common/instance.hpp index 8297b74e4..0702d513f 100644 --- a/src/viam/sdk/common/instance.hpp +++ b/src/viam/sdk/common/instance.hpp @@ -1,10 +1,12 @@ #pragma once -#include <viam/sdk/registry/registry.hpp> +#include <memory> namespace viam { namespace sdk { +class Registry; + /// @brief Instance management for Viam C++ SDK applications. /// This is a single instance class which is responsible for global setup and teardown related to /// the SDK. An Instance must be constructed before doing anything else in a program, and it must @@ -13,11 +15,13 @@ namespace sdk { class Instance { public: Instance(); + ~Instance(); - Registry& registry(); + Registry* registry(); private: - Registry registry_; + struct Impl; + std::unique_ptr<Impl> impl_; }; } // namespace sdk diff --git a/src/viam/sdk/module/service.cpp b/src/viam/sdk/module/service.cpp index 526beecb5..041fb90b3 100644 --- a/src/viam/sdk/module/service.cpp +++ b/src/viam/sdk/module/service.cpp @@ -57,7 +57,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { std::shared_ptr<Resource> res; const Dependencies deps = parent.get_dependencies_(&request->dependencies(), cfg.name()); const std::shared_ptr<const ModelRegistration> reg = - parent.registry_.lookup_model(cfg.api(), cfg.model()); + parent.registry_->lookup_model(cfg.api(), cfg.model()); if (reg) { try { res = reg->construct_resource(deps, cfg); @@ -112,7 +112,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { } const std::shared_ptr<const ModelRegistration> reg = - parent.registry_.lookup_model(cfg.name()); + parent.registry_->lookup_model(cfg.name()); if (reg) { try { const std::shared_ptr<Resource> res = reg->construct_resource(deps, cfg); @@ -132,7 +132,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { ResourceConfig cfg = from_proto(proto); const std::shared_ptr<const ModelRegistration> reg = - parent.registry_.lookup_model(cfg.api(), cfg.model()); + parent.registry_->lookup_model(cfg.api(), cfg.model()); if (!reg) { return grpc::Status(grpc::UNKNOWN, "unable to validate resource " + cfg.resource_name().name() + @@ -214,17 +214,17 @@ std::shared_ptr<Resource> ModuleService::get_parent_resource_(const Name& name) return parent_->resource_by_name(name); } -ModuleService::ModuleService(std::string addr, Registry& registry) +ModuleService::ModuleService(std::string addr, Registry* registry) : registry_(registry), module_(std::make_unique<Module>(std::move(addr))), - server_(std::make_unique<Server>(®istry_)) { + server_(std::make_unique<Server>(registry_)) { impl_ = std::make_unique<ServiceImpl>(*this); } ModuleService::ModuleService(int argc, char** argv, const std::vector<std::shared_ptr<ModelRegistration>>& registrations, - Registry& registry) + Registry* registry) : ModuleService( [argc, argv] { if (argc < 2) { @@ -237,7 +237,7 @@ ModuleService::ModuleService(int argc, set_logger_severity_from_args(argc, argv); for (auto&& mr : registrations) { - registry_.register_model(mr); + registry_->register_model(mr); add_model_from_registry(mr->api(), mr->model()); } } @@ -280,7 +280,7 @@ void ModuleService::add_model_from_registry_inlock_(API api, Model model, const std::lock_guard<std::mutex>&) { const std::shared_ptr<const ResourceServerRegistration> creator = - registry_.lookup_resource_server(api); + registry_->lookup_resource_server(api); std::string name; if (creator && creator->service_descriptor()) { name = creator->service_descriptor()->full_name(); diff --git a/src/viam/sdk/module/service.hpp b/src/viam/sdk/module/service.hpp index cffc47fe7..0927d26a8 100644 --- a/src/viam/sdk/module/service.hpp +++ b/src/viam/sdk/module/service.hpp @@ -31,7 +31,7 @@ class ModuleService { public: /// @brief Creates a new ModuleService that can serve on the provided socket. /// @param addr Address of socket to serve on. - explicit ModuleService(std::string addr, Registry& registry); + explicit ModuleService(std::string addr, Registry* registry); /// @brief Creates a new ModuleService. Socket path and log level will be /// inferred from passed in command line arguments, and passed in model @@ -42,7 +42,7 @@ class ModuleService { explicit ModuleService(int argc, char** argv, const std::vector<std::shared_ptr<ModelRegistration>>& registrations, - Registry& registry); + Registry* registry); ~ModuleService(); /// @brief Starts module. serve will return when SIGINT or SIGTERM is received @@ -65,7 +65,7 @@ class ModuleService { std::string const& resource_name); std::shared_ptr<Resource> get_parent_resource_(const Name& name); - Registry& registry_; + Registry* registry_; std::mutex lock_; std::unique_ptr<Module> module_; diff --git a/src/viam/sdk/registry/registry.hpp b/src/viam/sdk/registry/registry.hpp index 75e2324e3..43fa5c38f 100644 --- a/src/viam/sdk/registry/registry.hpp +++ b/src/viam/sdk/registry/registry.hpp @@ -185,7 +185,6 @@ class Registry { private: friend class Instance; - Registry() = default; /// @brief Initialized the Viam registry. No-op if it has already been called. diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index 6ac049eba..cb72451c7 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -178,7 +178,7 @@ void RobotClient::refresh() { // are being properly registered from name.subtype(), or update what we're // using for lookup const std::shared_ptr<const ResourceClientRegistration> rs = - registry_.lookup_resource_client({name.namespace_(), name.type(), name.subtype()}); + registry_->lookup_resource_client({name.namespace_(), name.type(), name.subtype()}); if (rs) { try { const std::shared_ptr<Resource> rpc_client = @@ -221,7 +221,7 @@ void RobotClient::refresh_every() { } }; -RobotClient::RobotClient(std::shared_ptr<ViamChannel> channel, Registry& registry) +RobotClient::RobotClient(std::shared_ptr<ViamChannel> channel, Registry* registry) : registry_(registry), channel_(channel->channel()), viam_channel_(std::move(channel)), @@ -235,7 +235,7 @@ std::vector<Name> RobotClient::resource_names() const { std::shared_ptr<RobotClient> RobotClient::with_channel(std::shared_ptr<ViamChannel> channel, const Options& options, - Registry& registry) { + Registry* registry) { std::shared_ptr<RobotClient> robot = std::make_shared<RobotClient>(std::move(channel), registry); robot->refresh_interval_ = options.refresh_interval(); @@ -256,7 +256,7 @@ std::shared_ptr<RobotClient> RobotClient::with_channel(std::shared_ptr<ViamChann std::shared_ptr<RobotClient> RobotClient::at_address(const std::string& address, const Options& options, - Registry& registry) { + Registry* registry) { const char* uri = address.c_str(); auto channel = ViamChannel::dial(uri, options.dial_options()); std::shared_ptr<RobotClient> robot = RobotClient::with_channel(channel, options, registry); @@ -267,7 +267,7 @@ std::shared_ptr<RobotClient> RobotClient::at_address(const std::string& address, std::shared_ptr<RobotClient> RobotClient::at_local_socket(const std::string& address, const Options& options, - Registry& registry) { + Registry* registry) { const std::string addr = "unix://" + address; const char* uri = addr.c_str(); const std::shared_ptr<grpc::Channel> channel = diff --git a/src/viam/sdk/robot/client.hpp b/src/viam/sdk/robot/client.hpp index 09834e1d8..0a9610ac2 100644 --- a/src/viam/sdk/robot/client.hpp +++ b/src/viam/sdk/robot/client.hpp @@ -12,14 +12,16 @@ #include <viam/sdk/common/utils.hpp> #include <viam/sdk/common/world_state.hpp> #include <viam/sdk/components/component.hpp> -#include <viam/sdk/registry/registry.hpp> #include <viam/sdk/resource/resource.hpp> +#include <viam/sdk/resource/resource_manager.hpp> #include <viam/sdk/rpc/dial.hpp> #include <viam/sdk/services/service.hpp> namespace viam { namespace sdk { +class Registry; + /// @defgroup Robot Classes related to a Robot representation. /// @class RobotClient client.hpp "robot/client.hpp" @@ -69,7 +71,7 @@ class RobotClient { /// @param options Options for connecting and refreshing. static std::shared_ptr<RobotClient> at_address(const std::string& address, const Options& options, - Registry& registry); + Registry* registry); /// @brief Creates a robot client connected to the robot at the provided local socket. /// @param address The local socket of the robot (a .sock file, etc.). @@ -78,7 +80,7 @@ class RobotClient { /// Only useful for connecting to robots across Unix sockets. static std::shared_ptr<RobotClient> at_local_socket(const std::string& address, const Options& options, - Registry& registry); + Registry* registry); /// @brief Creates a robot client connected to the provided channel. /// @param channel The channel to connect with. @@ -87,9 +89,9 @@ class RobotClient { /// `close()`d manually. static std::shared_ptr<RobotClient> with_channel(std::shared_ptr<ViamChannel> channel, const Options& options, - Registry& registry); + Registry* registry); - RobotClient(std::shared_ptr<ViamChannel> channel, Registry& registry); + RobotClient(std::shared_ptr<ViamChannel> channel, Registry* registry); std::vector<Name> resource_names() const; @@ -152,7 +154,7 @@ class RobotClient { status get_machine_status() const; private: - Registry& registry_; + Registry* registry_; std::vector<std::shared_ptr<std::thread>> threads_; diff --git a/src/viam/sdk/tests/mocks/mock_robot.cpp b/src/viam/sdk/tests/mocks/mock_robot.cpp index 8e28b944b..fdc068ec3 100644 --- a/src/viam/sdk/tests/mocks/mock_robot.cpp +++ b/src/viam/sdk/tests/mocks/mock_robot.cpp @@ -26,7 +26,7 @@ std::vector<Name> registered_models_for_resource(const std::shared_ptr<Resource> std::string resource_type; std::string resource_subtype; std::vector<Name> resource_names; - for (const auto& kv : GlobalInstance::registry().registered_models()) { + for (const auto& kv : GlobalInstance::registry()->registered_models()) { const std::shared_ptr<const ModelRegistration> reg = kv.second; if (reg->api() == resource->api()) { resource_type = reg->api().resource_type(); diff --git a/src/viam/sdk/tests/test_robot.cpp b/src/viam/sdk/tests/test_robot.cpp index e7ccc0de1..a7b403359 100644 --- a/src/viam/sdk/tests/test_robot.cpp +++ b/src/viam/sdk/tests/test_robot.cpp @@ -42,7 +42,7 @@ void robot_client_to_mocks_pipeline(F&& test_case) { rm->add(std::string("mock_generic"), generic::MockGenericComponent::get_mock_generic()); rm->add(std::string("mock_motor"), motor::MockMotor::get_mock_motor()); rm->add(std::string("mock_camera"), camera::MockCamera::get_mock_camera()); - auto server = std::make_shared<sdk::Server>(&GlobalInstance::registry()); + auto server = std::make_shared<sdk::Server>(GlobalInstance::registry()); MockRobotService service(rm, *server); server->start(); @@ -63,7 +63,7 @@ void robot_client_to_mocks_pipeline(F&& test_case) { } BOOST_AUTO_TEST_CASE(test_registering_resources) { - auto& registry = GlobalInstance::registry(); + auto& registry = *GlobalInstance::registry(); // To test with mock resources we need to be able to create them, which means registering // constructors. This tests that we register correctly. diff --git a/src/viam/sdk/tests/test_utils.hpp b/src/viam/sdk/tests/test_utils.hpp index c24bed482..655b34904 100644 --- a/src/viam/sdk/tests/test_utils.hpp +++ b/src/viam/sdk/tests/test_utils.hpp @@ -17,7 +17,7 @@ struct GlobalInstance { return inst; } - static sdk::Registry& registry() { + static sdk::Registry* registry() { return get().registry(); } }; @@ -61,7 +61,7 @@ class TestServer { // The passed in test_case function will have access to the created ResourceClient. template <typename ResourceType, typename F> void client_to_mock_pipeline(std::shared_ptr<Resource> mock, F&& test_case) { - auto server = std::make_shared<sdk::Server>(&GlobalInstance::registry()); + auto server = std::make_shared<sdk::Server>(GlobalInstance::registry()); // normally the high level server service (either robot or module) handles adding managed // resources, but in this case we must do it ourselves. @@ -74,7 +74,7 @@ void client_to_mock_pipeline(std::shared_ptr<Resource> mock, F&& test_case) { auto grpc_channel = test_server.grpc_in_process_channel(); auto resource_client = GlobalInstance::registry() - .lookup_resource_client(API::get<ResourceType>()) + ->lookup_resource_client(API::get<ResourceType>()) ->create_rpc_client(mock->name(), std::move(grpc_channel)); // Run the passed-in test case on the created stack and give access to the From e5cf6d054c82a4dff634ec64b5eb95e3c2a5426c Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 25 Feb 2025 15:37:51 -0500 Subject: [PATCH 08/86] add instance management infra --- .../modules/complex/test_complex_module.cpp | 2 +- src/viam/sdk/common/instance.cpp | 41 ++++++++++++++++++- src/viam/sdk/common/instance.hpp | 2 + src/viam/sdk/tests/mocks/mock_robot.cpp | 2 +- src/viam/sdk/tests/test_robot.cpp | 6 +-- src/viam/sdk/tests/test_utils.hpp | 16 ++------ 6 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/viam/examples/modules/complex/test_complex_module.cpp b/src/viam/examples/modules/complex/test_complex_module.cpp index 228ef96c7..3f4d4ee3d 100644 --- a/src/viam/examples/modules/complex/test_complex_module.cpp +++ b/src/viam/examples/modules/complex/test_complex_module.cpp @@ -24,7 +24,7 @@ using namespace viam::sdktests; struct RegisterGizmoAndSummationFixture { RegisterGizmoAndSummationFixture() { - auto* registry = GlobalInstance::registry(); + auto* registry = Instance::current().registry(); registry->register_resource<GizmoClient, GizmoServer>(); registry->register_resource<SummationClient, SummationServer>(); } diff --git a/src/viam/sdk/common/instance.cpp b/src/viam/sdk/common/instance.cpp index c356aee54..9b6a7eccc 100644 --- a/src/viam/sdk/common/instance.cpp +++ b/src/viam/sdk/common/instance.cpp @@ -1,19 +1,56 @@ #include <viam/sdk/common/instance.hpp> +#include <viam/sdk/common/exception.hpp> #include <viam/sdk/registry/registry.hpp> +#include <atomic> + namespace viam { namespace sdk { +namespace { + +// Memory region sentinel to check if object is being destroyed. +std::aligned_storage_t<sizeof(Instance), alignof(Instance)> sentinel; + +std::atomic<Instance*> current_instance{nullptr}; + +} // namespace + struct Instance::Impl { Registry registry; }; -Instance::Instance() : impl_(std::make_unique<Instance::Impl>()) { +Instance::Instance() { + Instance* expected = nullptr; + + if (!current_instance.compare_exchange_strong(expected, this)) { + throw Exception("tried to create duplicate instance"); + } + + impl_ = std::make_unique<Instance::Impl>(); impl_->registry.initialize(); } -Instance::~Instance() = default; +Instance::~Instance() { + current_instance.store(reinterpret_cast<Instance*>(&sentinel)); + impl_.reset(); +} + +Instance& Instance::current() { + if (!current_instance.load()) { + // This variable declaration calls the default ctor, storing a current instance. + static Instance inst; + } + + Instance* current = current_instance.load(); + + if (current == reinterpret_cast<Instance*>(&sentinel)) { + throw Exception("instance was destroyed"); + } + + return *current; +} Registry* Instance::registry() { return &(impl_->registry); diff --git a/src/viam/sdk/common/instance.hpp b/src/viam/sdk/common/instance.hpp index 0702d513f..c1ab0961f 100644 --- a/src/viam/sdk/common/instance.hpp +++ b/src/viam/sdk/common/instance.hpp @@ -17,6 +17,8 @@ class Instance { Instance(); ~Instance(); + static Instance& current(); + Registry* registry(); private: diff --git a/src/viam/sdk/tests/mocks/mock_robot.cpp b/src/viam/sdk/tests/mocks/mock_robot.cpp index fdc068ec3..5dc03fcc2 100644 --- a/src/viam/sdk/tests/mocks/mock_robot.cpp +++ b/src/viam/sdk/tests/mocks/mock_robot.cpp @@ -26,7 +26,7 @@ std::vector<Name> registered_models_for_resource(const std::shared_ptr<Resource> std::string resource_type; std::string resource_subtype; std::vector<Name> resource_names; - for (const auto& kv : GlobalInstance::registry()->registered_models()) { + for (const auto& kv : Instance::current().registry()->registered_models()) { const std::shared_ptr<const ModelRegistration> reg = kv.second; if (reg->api() == resource->api()) { resource_type = reg->api().resource_type(); diff --git a/src/viam/sdk/tests/test_robot.cpp b/src/viam/sdk/tests/test_robot.cpp index a7b403359..e3bead0c9 100644 --- a/src/viam/sdk/tests/test_robot.cpp +++ b/src/viam/sdk/tests/test_robot.cpp @@ -42,7 +42,7 @@ void robot_client_to_mocks_pipeline(F&& test_case) { rm->add(std::string("mock_generic"), generic::MockGenericComponent::get_mock_generic()); rm->add(std::string("mock_motor"), motor::MockMotor::get_mock_motor()); rm->add(std::string("mock_camera"), camera::MockCamera::get_mock_camera()); - auto server = std::make_shared<sdk::Server>(GlobalInstance::registry()); + auto server = std::make_shared<sdk::Server>(Instance::current().registry()); MockRobotService service(rm, *server); server->start(); @@ -52,7 +52,7 @@ void robot_client_to_mocks_pipeline(F&& test_case) { auto grpc_channel = test_server.grpc_in_process_channel(); auto viam_channel = std::make_shared<ViamChannel>(grpc_channel, "", nullptr); auto client = RobotClient::with_channel( - viam_channel, Options(0, boost::none), GlobalInstance::registry()); + viam_channel, Options(0, boost::none), Instance::current().registry()); // Run the passed-in test case on the created stack and give access to the // created RobotClient and MockRobotService. @@ -63,7 +63,7 @@ void robot_client_to_mocks_pipeline(F&& test_case) { } BOOST_AUTO_TEST_CASE(test_registering_resources) { - auto& registry = *GlobalInstance::registry(); + auto& registry = *Instance::current().registry(); // To test with mock resources we need to be able to create them, which means registering // constructors. This tests that we register correctly. diff --git a/src/viam/sdk/tests/test_utils.hpp b/src/viam/sdk/tests/test_utils.hpp index 655b34904..e5c6fb729 100644 --- a/src/viam/sdk/tests/test_utils.hpp +++ b/src/viam/sdk/tests/test_utils.hpp @@ -11,17 +11,6 @@ namespace viam { namespace sdktests { -struct GlobalInstance { - static sdk::Instance& get() { - static sdk::Instance inst; - return inst; - } - - static sdk::Registry* registry() { - return get().registry(); - } -}; - using namespace viam::sdk; ProtoStruct fake_map(); @@ -61,7 +50,7 @@ class TestServer { // The passed in test_case function will have access to the created ResourceClient. template <typename ResourceType, typename F> void client_to_mock_pipeline(std::shared_ptr<Resource> mock, F&& test_case) { - auto server = std::make_shared<sdk::Server>(GlobalInstance::registry()); + auto server = std::make_shared<sdk::Server>(sdk::Instance::current().registry()); // normally the high level server service (either robot or module) handles adding managed // resources, but in this case we must do it ourselves. @@ -73,7 +62,8 @@ void client_to_mock_pipeline(std::shared_ptr<Resource> mock, F&& test_case) { auto test_server = TestServer(server); auto grpc_channel = test_server.grpc_in_process_channel(); - auto resource_client = GlobalInstance::registry() + auto resource_client = sdk::Instance::current() + .registry() ->lookup_resource_client(API::get<ResourceType>()) ->create_rpc_client(mock->name(), std::move(grpc_channel)); From 5024d3a2d6be053ee8b088ede5746475c2298477 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 25 Feb 2025 15:43:04 -0500 Subject: [PATCH 09/86] update tflite module --- src/viam/examples/modules/tflite/main.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/viam/examples/modules/tflite/main.cpp b/src/viam/examples/modules/tflite/main.cpp index 44cd8e284..e1c806354 100644 --- a/src/viam/examples/modules/tflite/main.cpp +++ b/src/viam/examples/modules/tflite/main.cpp @@ -23,6 +23,7 @@ #include <tensorflow/lite/c/c_api.h> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/components/component.hpp> #include <viam/sdk/config/resource.hpp> @@ -723,6 +724,10 @@ class MLModelServiceTFLite : public vsdk::MLModelService, }; int serve(const std::string& socket_path) try { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + vsdk::Instance inst; + // Create a new model registration for the service. auto module_registration = std::make_shared<vsdk::ModelRegistration>( // Identify that this resource offers the MLModelService API @@ -737,10 +742,10 @@ int serve(const std::string& socket_path) try { }); // Register the newly created registration with the Registry. - vsdk::Registry::register_model(module_registration); + inst.registry()->register_model(module_registration); // Construct the module service and tell it where to place the socket path. - auto module_service = std::make_shared<vsdk::ModuleService>(socket_path); + auto module_service = std::make_shared<vsdk::ModuleService>(socket_path, inst.registry()); // Add the server as providing the API and model declared in the // registration. From ef8ec8eff50e91c87c23dcc3a34f26611fe48ccc Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 25 Feb 2025 15:59:35 -0500 Subject: [PATCH 10/86] silence spurious const warning --- src/viam/sdk/common/instance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/viam/sdk/common/instance.cpp b/src/viam/sdk/common/instance.cpp index 9b6a7eccc..c366ad6c6 100644 --- a/src/viam/sdk/common/instance.cpp +++ b/src/viam/sdk/common/instance.cpp @@ -40,7 +40,7 @@ Instance::~Instance() { Instance& Instance::current() { if (!current_instance.load()) { // This variable declaration calls the default ctor, storing a current instance. - static Instance inst; + static Instance inst; // NOLINT (misc-const-correctness) } Instance* current = current_instance.load(); From 16113fd4dd38f44e8481c3468eba258b22296941 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 25 Feb 2025 16:27:29 -0500 Subject: [PATCH 11/86] make method static --- src/viam/sdk/registry/registry.cpp | 2 +- src/viam/sdk/registry/registry.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/viam/sdk/registry/registry.cpp b/src/viam/sdk/registry/registry.cpp index 71e3e7711..db28f628b 100644 --- a/src/viam/sdk/registry/registry.cpp +++ b/src/viam/sdk/registry/registry.cpp @@ -163,7 +163,7 @@ std::shared_ptr<const ResourceClientRegistration> Registry::lookup_resource_clie } const google::protobuf::ServiceDescriptor* Registry::get_service_descriptor_( - const char* service_full_name) const { + const char* service_full_name) { const google::protobuf::DescriptorPool* p = google::protobuf::DescriptorPool::generated_pool(); const google::protobuf::ServiceDescriptor* sd = p->FindServiceByName(service_full_name); if (!sd) { diff --git a/src/viam/sdk/registry/registry.hpp b/src/viam/sdk/registry/registry.hpp index 43fa5c38f..db476be97 100644 --- a/src/viam/sdk/registry/registry.hpp +++ b/src/viam/sdk/registry/registry.hpp @@ -204,8 +204,8 @@ class Registry { void register_resource_client_( API api, std::shared_ptr<ResourceClientRegistration> resource_registration); - const google::protobuf::ServiceDescriptor* get_service_descriptor_( - const char* service_full_name) const; + static const google::protobuf::ServiceDescriptor* get_service_descriptor_( + const char* service_full_name); std::shared_ptr<const ModelRegistration> lookup_model_inlock_( const std::string& name, const std::lock_guard<std::mutex>&) const; From dbf1647b0a4074b0f260d59fb531a6ce57992a14 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 26 Feb 2025 11:33:05 -0500 Subject: [PATCH 12/86] update cml boost links --- CMakeLists.txt | 2 +- src/viam/sdk/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 25fc45b3b..d05467cf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -324,7 +324,7 @@ set(VIAMCPPSDK_XTL_VERSION_MINIMUM 0.7.2) set(VIAMCPPSDK_XTENSOR_VERSION_MINIMUM 0.24.3) # Time to find `BOOST`. -find_package(Boost ${VIAMCPPSDK_BOOST_VERSION_MINIMUM} REQUIRED COMPONENTS headers log program_options) +find_package(Boost ${VIAMCPPSDK_BOOST_VERSION_MINIMUM} REQUIRED COMPONENTS headers log log_setup program_options) # Time to find `protobuf` and `gRPC[++]`. Normally this would just be # something like `find_package(gRPC <version> CONFIG REQUIRED)`, and diff --git a/src/viam/sdk/CMakeLists.txt b/src/viam/sdk/CMakeLists.txt index b69b586f9..0ba964cc3 100644 --- a/src/viam/sdk/CMakeLists.txt +++ b/src/viam/sdk/CMakeLists.txt @@ -244,6 +244,7 @@ viamcppsdk_link_viam_api(viamsdk PRIVATE) target_link_libraries(viamsdk PUBLIC Boost::headers PUBLIC Boost::log + PUBLIC Boost::log_setup PUBLIC xtensor PRIVATE ${VIAMCPPSDK_GRPCXX_REFLECTION_LIBRARIES} PRIVATE ${VIAMCPPSDK_GRPCXX_LIBRARIES} From d1dffb80fcf400b11f495a722102de392288640e Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 27 Feb 2025 12:49:51 -0500 Subject: [PATCH 13/86] add logger to resource --- src/viam/sdk/resource/resource.cpp | 5 ++++- src/viam/sdk/resource/resource.hpp | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/viam/sdk/resource/resource.cpp b/src/viam/sdk/resource/resource.cpp index caf4b94d1..48bbb0f37 100644 --- a/src/viam/sdk/resource/resource.cpp +++ b/src/viam/sdk/resource/resource.cpp @@ -1,5 +1,7 @@ #include <viam/sdk/resource/resource.hpp> +#include <boost/log/keywords/channel.hpp> + #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/common/utils.hpp> #include <viam/sdk/registry/registry.hpp> @@ -9,7 +11,8 @@ namespace viam { namespace sdk { Resource::~Resource() = default; -Resource::Resource(std::string name) : name_(std::move(name)) {} +Resource::Resource(std::string name) + : name_(std::move(name)), logger_(boost::log::keywords::channel = name_) {} std::string Resource::name() const { return name_; diff --git a/src/viam/sdk/resource/resource.hpp b/src/viam/sdk/resource/resource.hpp index dcf9f4363..d61e5eb04 100644 --- a/src/viam/sdk/resource/resource.hpp +++ b/src/viam/sdk/resource/resource.hpp @@ -2,6 +2,9 @@ #include <unordered_map> +#include <boost/log/sources/severity_channel_logger.hpp> +#include <boost/log/trivial.hpp> + #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/config/resource.hpp> #include <viam/sdk/resource/resource_api.hpp> @@ -30,6 +33,8 @@ class Resource { protected: Name get_resource_name(const std::string& type) const; + + boost::log::sources::severity_channel_logger_mt<boost::log::trivial::severity_level> logger_; }; template <> From 4771390555ed6fdad2220d138e4ab770bb8b7b43 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 27 Feb 2025 13:48:18 -0500 Subject: [PATCH 14/86] use static current to populate registry member --- src/viam/examples/camera/example_camera.cpp | 8 +----- src/viam/examples/dial/example_dial.cpp | 7 +---- .../dial_api_key/example_dial_api_key.cpp | 7 +---- .../example_audio_classification_client.cpp | 9 ++----- src/viam/examples/modules/complex/client.cpp | 11 +++----- src/viam/examples/modules/complex/main.cpp | 11 +++----- .../modules/complex/test_complex_module.cpp | 5 ++-- src/viam/examples/modules/simple/client.cpp | 5 +--- src/viam/examples/modules/simple/main.cpp | 5 +--- src/viam/examples/modules/tflite/main.cpp | 9 ++----- src/viam/examples/motor/example_motor.cpp | 8 +----- src/viam/sdk/module/service.cpp | 27 +++++++++---------- src/viam/sdk/module/service.hpp | 5 ++-- src/viam/sdk/registry/registry.cpp | 5 ++++ src/viam/sdk/registry/registry.hpp | 3 +++ src/viam/sdk/robot/client.cpp | 20 ++++++-------- src/viam/sdk/robot/client.hpp | 24 ++++------------- src/viam/sdk/rpc/server.cpp | 4 +-- src/viam/sdk/rpc/server.hpp | 4 +-- src/viam/sdk/tests/test_robot.cpp | 7 +++-- src/viam/sdk/tests/test_utils.hpp | 7 +++-- 21 files changed, 62 insertions(+), 129 deletions(-) diff --git a/src/viam/examples/camera/example_camera.cpp b/src/viam/examples/camera/example_camera.cpp index b0202a27e..bc1b0ab9a 100644 --- a/src/viam/examples/camera/example_camera.cpp +++ b/src/viam/examples/camera/example_camera.cpp @@ -3,7 +3,6 @@ #include <unistd.h> #include <vector> -#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/camera.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -14,11 +13,6 @@ int main() { using std::endl; namespace vs = ::viam::sdk; try { - // Every Viam C++ SDK program must have one and only one Instance object which is created - // before - // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. - vs::Instance inst; - // If you want to connect to a remote robot, this should be the url of the robot // Ex: xxx.xxx.viam.cloud std::string robot_address("localhost:8080"); @@ -41,7 +35,7 @@ int main() { std::shared_ptr<vs::RobotClient> robot; try { - robot = vs::RobotClient::at_address(robot_address, options, inst.registry()); + robot = vs::RobotClient::at_address(robot_address, options); cout << "Successfully connected to the robot" << endl; } catch (const std::exception& e) { cerr << "Failed to connect to the robot. Exiting." << endl; diff --git a/src/viam/examples/dial/example_dial.cpp b/src/viam/examples/dial/example_dial.cpp index 28ccd7659..efa783dfb 100644 --- a/src/viam/examples/dial/example_dial.cpp +++ b/src/viam/examples/dial/example_dial.cpp @@ -9,7 +9,6 @@ #include <boost/optional.hpp> -#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/generic.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -17,10 +16,6 @@ using namespace viam::sdk; int main() { - // Every Viam C++ SDK program must have one and only one Instance object which is created before - // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. - Instance inst; - const char* uri = "<your robot URI here>"; DialOptions dial_options; std::string type = "<your authentication type>"; @@ -32,7 +27,7 @@ int main() { Options options(1, opts); // connect to robot, ensure we can refresh it - std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options, inst.registry()); + std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options); // ensure we can query resources std::vector<Name> resource_names = robot->resource_names(); diff --git a/src/viam/examples/dial_api_key/example_dial_api_key.cpp b/src/viam/examples/dial_api_key/example_dial_api_key.cpp index 7c9e82fef..4c47beffe 100644 --- a/src/viam/examples/dial_api_key/example_dial_api_key.cpp +++ b/src/viam/examples/dial_api_key/example_dial_api_key.cpp @@ -10,7 +10,6 @@ #include <boost/optional.hpp> #include <boost/program_options.hpp> -#include <viam/sdk/common/instance.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -19,10 +18,6 @@ using namespace viam::sdk; namespace po = boost::program_options; int main(int argc, char* argv[]) { - // Every Viam C++ SDK program must have one and only one Instance object which is created before - // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. - Instance inst; - po::options_description desc("Allowed options"); desc.add_options()("help", "List options and exit")( "uri", po::value<std::string>(), "URI of robot")( @@ -46,7 +41,7 @@ int main(int argc, char* argv[]) { // connect to robot, ensure we can refresh it std::shared_ptr<RobotClient> robot = - RobotClient::at_address(vm["uri"].as<std::string>(), options, inst.registry()); + RobotClient::at_address(vm["uri"].as<std::string>(), options); // ensure we can query resources std::vector<Name> resource_names = robot->resource_names(); diff --git a/src/viam/examples/mlmodel/example_audio_classification_client.cpp b/src/viam/examples/mlmodel/example_audio_classification_client.cpp index ab06a082e..95e26f57c 100644 --- a/src/viam/examples/mlmodel/example_audio_classification_client.cpp +++ b/src/viam/examples/mlmodel/example_audio_classification_client.cpp @@ -29,7 +29,6 @@ #include <boost/program_options.hpp> #include <boost/variant/get.hpp> -#include <viam/sdk/common/instance.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/services/mlmodel.hpp> @@ -79,10 +78,6 @@ constexpr char kRobotConfigTemplate[] = R"( } // namespace int main(int argc, char* argv[]) try { - // Every Viam C++ SDK program must have one and only one Instance object which is created before - // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. - viam::sdk::Instance inst; - // Build up our command line options. The example operates in two // modes. In the "--generate" mode, it takes command line // parameters needed to satisfy the interpolation points in the @@ -239,8 +234,8 @@ int main(int argc, char* argv[]) try { dial_options.set_entity(opt_api_key_id.get()); dial_options.set_credentials(viam::sdk::Credentials("api-key", opt_api_key.get())); - auto robot = vsdk::RobotClient::at_address( - opt_robot_host.get(), {0, {std::move(dial_options)}}, inst.registry()); + auto robot = + vsdk::RobotClient::at_address(opt_robot_host.get(), {0, {std::move(dial_options)}}); // Obtain a handle to the MLModelService module on the robot. Note that the string // `yamnet_classification_tflite` is arbitrary. It just matches what was used to name the diff --git a/src/viam/examples/modules/complex/client.cpp b/src/viam/examples/modules/complex/client.cpp index ea3444844..ac85c9f00 100644 --- a/src/viam/examples/modules/complex/client.cpp +++ b/src/viam/examples/modules/complex/client.cpp @@ -11,7 +11,6 @@ #include <grpcpp/grpcpp.h> #include <grpcpp/support/status.h> -#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/motor.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -22,10 +21,6 @@ using namespace viam::sdk; int main() { - // Every Viam C++ SDK program must have one and only one Instance object which is created before - // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. - Instance inst; - const char* uri = "http://localhost:8080/"; // replace with your URI if connecting securely DialOptions dial_options; dial_options.set_allow_insecure_downgrade(true); // set to false if connecting securely @@ -42,11 +37,11 @@ int main() { // Register custom gizmo and summation clients so robot client can access resources // of that type from the server. - inst.registry()->register_resource_client<GizmoClient>(); - inst.registry()->register_resource_client<SummationClient>(); + Registry::get().register_resource_client<GizmoClient>(); + Registry::get().register_resource_client<SummationClient>(); // Connect to robot. - std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options, inst.registry()); + std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options); // Print resources. std::cout << "Resources" << std::endl; std::vector<Name> resource_names = robot->resource_names(); diff --git a/src/viam/examples/modules/complex/main.cpp b/src/viam/examples/modules/complex/main.cpp index 5d3f85f67..da80453e6 100644 --- a/src/viam/examples/modules/complex/main.cpp +++ b/src/viam/examples/modules/complex/main.cpp @@ -5,7 +5,6 @@ #include <grpcpp/grpcpp.h> #include <grpcpp/server_context.h> -#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/base.hpp> #include <viam/sdk/components/component.hpp> #include <viam/sdk/config/resource.hpp> @@ -25,15 +24,11 @@ using namespace viam::sdk; int main(int argc, char** argv) { - // Every Viam C++ SDK program must have one and only one Instance object which is created before - // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. - Instance inst; - Model mybase_model("viam", "base", "mybase"); // Make sure to explicity register resources with custom APIs. - inst.registry()->register_resource_server<GizmoServer>(); - inst.registry()->register_resource_server<SummationServer>(); + Registry::get().register_resource_server<GizmoServer>(); + Registry::get().register_resource_server<SummationServer>(); std::shared_ptr<ModelRegistration> mybase_mr = std::make_shared<ModelRegistration>( API::get<Base>(), @@ -56,7 +51,7 @@ int main(int argc, char** argv) { }); std::vector<std::shared_ptr<ModelRegistration>> mrs = {mybase_mr, mygizmo_mr, mysummation_mr}; - auto my_mod = std::make_shared<ModuleService>(argc, argv, mrs, inst.registry()); + auto my_mod = std::make_shared<ModuleService>(argc, argv, mrs); my_mod->serve(); return EXIT_SUCCESS; diff --git a/src/viam/examples/modules/complex/test_complex_module.cpp b/src/viam/examples/modules/complex/test_complex_module.cpp index 3f4d4ee3d..14d68a8cf 100644 --- a/src/viam/examples/modules/complex/test_complex_module.cpp +++ b/src/viam/examples/modules/complex/test_complex_module.cpp @@ -24,9 +24,8 @@ using namespace viam::sdktests; struct RegisterGizmoAndSummationFixture { RegisterGizmoAndSummationFixture() { - auto* registry = Instance::current().registry(); - registry->register_resource<GizmoClient, GizmoServer>(); - registry->register_resource<SummationClient, SummationServer>(); + Registry::get().register_resource<GizmoClient, GizmoServer>(); + Registry::get().register_resource<SummationClient, SummationServer>(); } // Test teardown is a noop; diff --git a/src/viam/examples/modules/simple/client.cpp b/src/viam/examples/modules/simple/client.cpp index ac014d1e7..fcaab5eff 100644 --- a/src/viam/examples/modules/simple/client.cpp +++ b/src/viam/examples/modules/simple/client.cpp @@ -2,7 +2,6 @@ #include <memory> #include <string> -#include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/components/sensor.hpp> #include <viam/sdk/robot/client.hpp> @@ -11,8 +10,6 @@ using namespace viam::sdk; int main() { - Instance inst; - const char* uri = "http://localhost:8080/"; // replace with your URI if connecting securely DialOptions dial_options; dial_options.set_allow_insecure_downgrade(true); // set to false if connecting securely @@ -27,7 +24,7 @@ int main() { std::string address(uri); Options options(1, opts); - std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options, inst.registry()); + std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options); // Print resources std::cout << "Resources\n"; diff --git a/src/viam/examples/modules/simple/main.cpp b/src/viam/examples/modules/simple/main.cpp index b899d3b44..cfd783f66 100644 --- a/src/viam/examples/modules/simple/main.cpp +++ b/src/viam/examples/modules/simple/main.cpp @@ -3,7 +3,6 @@ #include <sstream> #include <viam/sdk/common/exception.hpp> -#include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/components/sensor.hpp> #include <viam/sdk/config/resource.hpp> @@ -76,8 +75,6 @@ ProtoStruct MySensor::get_readings(const ProtoStruct&) { } int main(int argc, char** argv) try { - Instance inst; - Model mysensor_model("viam", "sensor", "mysensor"); std::shared_ptr<ModelRegistration> mr = std::make_shared<ModelRegistration>( @@ -87,7 +84,7 @@ int main(int argc, char** argv) try { &MySensor::validate); std::vector<std::shared_ptr<ModelRegistration>> mrs = {mr}; - auto my_mod = std::make_shared<ModuleService>(argc, argv, mrs, inst.registry()); + auto my_mod = std::make_shared<ModuleService>(argc, argv, mrs); my_mod->serve(); return EXIT_SUCCESS; diff --git a/src/viam/examples/modules/tflite/main.cpp b/src/viam/examples/modules/tflite/main.cpp index e1c806354..44cd8e284 100644 --- a/src/viam/examples/modules/tflite/main.cpp +++ b/src/viam/examples/modules/tflite/main.cpp @@ -23,7 +23,6 @@ #include <tensorflow/lite/c/c_api.h> -#include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/components/component.hpp> #include <viam/sdk/config/resource.hpp> @@ -724,10 +723,6 @@ class MLModelServiceTFLite : public vsdk::MLModelService, }; int serve(const std::string& socket_path) try { - // Every Viam C++ SDK program must have one and only one Instance object which is created before - // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. - vsdk::Instance inst; - // Create a new model registration for the service. auto module_registration = std::make_shared<vsdk::ModelRegistration>( // Identify that this resource offers the MLModelService API @@ -742,10 +737,10 @@ int serve(const std::string& socket_path) try { }); // Register the newly created registration with the Registry. - inst.registry()->register_model(module_registration); + vsdk::Registry::register_model(module_registration); // Construct the module service and tell it where to place the socket path. - auto module_service = std::make_shared<vsdk::ModuleService>(socket_path, inst.registry()); + auto module_service = std::make_shared<vsdk::ModuleService>(socket_path); // Add the server as providing the API and model declared in the // registration. diff --git a/src/viam/examples/motor/example_motor.cpp b/src/viam/examples/motor/example_motor.cpp index 1a5ff50b7..c4d8023d5 100644 --- a/src/viam/examples/motor/example_motor.cpp +++ b/src/viam/examples/motor/example_motor.cpp @@ -6,7 +6,6 @@ #include <string> #include <vector> -#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/motor.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -28,11 +27,6 @@ int main() { namespace vs = ::viam::sdk; try { - // Every Viam C++ SDK program must have one and only one Instance object which is created - // before any other C++ SDK objects and stays alive until all Viam C++ SDK objects are - // destroyed. - vs::Instance inst; - // If you want to connect to a remote robot, this should be the url of the robot // Ex: xxx.xxx.viam.cloud std::string robot_address("localhost:8080"); @@ -55,7 +49,7 @@ int main() { std::shared_ptr<vs::RobotClient> robot; try { - robot = vs::RobotClient::at_address(robot_address, options, inst.registry()); + robot = vs::RobotClient::at_address(robot_address, options); cout << "Successfully connected to the robot" << endl; } catch (const std::exception& e) { cerr << "Failed to connect to the robot. Exiting." << endl; diff --git a/src/viam/sdk/module/service.cpp b/src/viam/sdk/module/service.cpp index 041fb90b3..d644b5420 100644 --- a/src/viam/sdk/module/service.cpp +++ b/src/viam/sdk/module/service.cpp @@ -208,32 +208,29 @@ Dependencies ModuleService::get_dependencies_( std::shared_ptr<Resource> ModuleService::get_parent_resource_(const Name& name) { if (!parent_) { - parent_ = RobotClient::at_local_socket(parent_addr_, {0, boost::none}, registry_); + parent_ = RobotClient::at_local_socket(parent_addr_, {0, boost::none}); } return parent_->resource_by_name(name); } -ModuleService::ModuleService(std::string addr, Registry* registry) - : registry_(registry), +ModuleService::ModuleService(std::string addr) + : registry_(&Registry::get()), module_(std::make_unique<Module>(std::move(addr))), - server_(std::make_unique<Server>(registry_)) { + server_(std::make_unique<Server>()) { impl_ = std::make_unique<ServiceImpl>(*this); } ModuleService::ModuleService(int argc, char** argv, - const std::vector<std::shared_ptr<ModelRegistration>>& registrations, - Registry* registry) - : ModuleService( - [argc, argv] { - if (argc < 2) { - throw Exception(ErrorCondition::k_connection, - "Need socket path as command line argument"); - } - return argv[1]; - }(), - registry) { + const std::vector<std::shared_ptr<ModelRegistration>>& registrations) + : ModuleService([argc, argv] { + if (argc < 2) { + throw Exception(ErrorCondition::k_connection, + "Need socket path as command line argument"); + } + return argv[1]; + }()) { set_logger_severity_from_args(argc, argv); for (auto&& mr : registrations) { diff --git a/src/viam/sdk/module/service.hpp b/src/viam/sdk/module/service.hpp index 0927d26a8..95a7ad4f3 100644 --- a/src/viam/sdk/module/service.hpp +++ b/src/viam/sdk/module/service.hpp @@ -31,7 +31,7 @@ class ModuleService { public: /// @brief Creates a new ModuleService that can serve on the provided socket. /// @param addr Address of socket to serve on. - explicit ModuleService(std::string addr, Registry* registry); + explicit ModuleService(std::string addr); /// @brief Creates a new ModuleService. Socket path and log level will be /// inferred from passed in command line arguments, and passed in model @@ -41,8 +41,7 @@ class ModuleService { /// @param registrations Models to register and add to the module. explicit ModuleService(int argc, char** argv, - const std::vector<std::shared_ptr<ModelRegistration>>& registrations, - Registry* registry); + const std::vector<std::shared_ptr<ModelRegistration>>& registrations); ~ModuleService(); /// @brief Starts module. serve will return when SIGINT or SIGTERM is received diff --git a/src/viam/sdk/registry/registry.cpp b/src/viam/sdk/registry/registry.cpp index 8f7209adf..1ee9b5533 100644 --- a/src/viam/sdk/registry/registry.cpp +++ b/src/viam/sdk/registry/registry.cpp @@ -12,6 +12,7 @@ #include <grpcpp/ext/proto_server_reflection_plugin.h> #include <viam/sdk/common/exception.hpp> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/private/arm_client.hpp> #include <viam/sdk/components/private/arm_server.hpp> #include <viam/sdk/components/private/base_client.hpp> @@ -90,6 +91,10 @@ const Model& ModelRegistration::model() const { return model_; }; +Registry& Registry::get() { + return *Instance::current().registry(); +} + void Registry::register_model(std::shared_ptr<const ModelRegistration> resource) { std::string reg_key = resource->api().to_string() + "/" + resource->model().to_string(); if (resources_.find(reg_key) != resources_.end()) { diff --git a/src/viam/sdk/registry/registry.hpp b/src/viam/sdk/registry/registry.hpp index db476be97..f09ee2d62 100644 --- a/src/viam/sdk/registry/registry.hpp +++ b/src/viam/sdk/registry/registry.hpp @@ -103,6 +103,9 @@ class ModelRegistration { /// @brief A registry of known resources. class Registry { public: + /// @brief Get the application-wide instance of Registry. + static Registry& get(); + /// @brief Registers a resource with the Registry. /// @param resource An object containing resource registration information. /// @throws `Exception` if the resource has already been registered. diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index cb72451c7..a8cb16c75 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -221,8 +221,8 @@ void RobotClient::refresh_every() { } }; -RobotClient::RobotClient(std::shared_ptr<ViamChannel> channel, Registry* registry) - : registry_(registry), +RobotClient::RobotClient(std::shared_ptr<ViamChannel> channel) + : registry_(&Registry::get()), channel_(channel->channel()), viam_channel_(std::move(channel)), should_close_channel_(false), @@ -234,10 +234,8 @@ std::vector<Name> RobotClient::resource_names() const { } std::shared_ptr<RobotClient> RobotClient::with_channel(std::shared_ptr<ViamChannel> channel, - const Options& options, - Registry* registry) { - std::shared_ptr<RobotClient> robot = - std::make_shared<RobotClient>(std::move(channel), registry); + const Options& options) { + std::shared_ptr<RobotClient> robot = std::make_shared<RobotClient>(std::move(channel)); robot->refresh_interval_ = options.refresh_interval(); robot->should_refresh_ = (robot->refresh_interval_ > 0); if (robot->should_refresh_) { @@ -255,25 +253,23 @@ std::shared_ptr<RobotClient> RobotClient::with_channel(std::shared_ptr<ViamChann }; std::shared_ptr<RobotClient> RobotClient::at_address(const std::string& address, - const Options& options, - Registry* registry) { + const Options& options) { const char* uri = address.c_str(); auto channel = ViamChannel::dial(uri, options.dial_options()); - std::shared_ptr<RobotClient> robot = RobotClient::with_channel(channel, options, registry); + std::shared_ptr<RobotClient> robot = RobotClient::with_channel(channel, options); robot->should_close_channel_ = true; return robot; }; std::shared_ptr<RobotClient> RobotClient::at_local_socket(const std::string& address, - const Options& options, - Registry* registry) { + const Options& options) { const std::string addr = "unix://" + address; const char* uri = addr.c_str(); const std::shared_ptr<grpc::Channel> channel = sdk::impl::create_viam_channel(uri, grpc::InsecureChannelCredentials()); auto viam_channel = std::make_shared<ViamChannel>(channel, address.c_str(), nullptr); - std::shared_ptr<RobotClient> robot = RobotClient::with_channel(viam_channel, options, registry); + std::shared_ptr<RobotClient> robot = RobotClient::with_channel(viam_channel, options); robot->should_close_channel_ = true; return robot; diff --git a/src/viam/sdk/robot/client.hpp b/src/viam/sdk/robot/client.hpp index 0a9610ac2..410abca28 100644 --- a/src/viam/sdk/robot/client.hpp +++ b/src/viam/sdk/robot/client.hpp @@ -12,16 +12,14 @@ #include <viam/sdk/common/utils.hpp> #include <viam/sdk/common/world_state.hpp> #include <viam/sdk/components/component.hpp> +#include <viam/sdk/registry/registry.hpp> #include <viam/sdk/resource/resource.hpp> -#include <viam/sdk/resource/resource_manager.hpp> #include <viam/sdk/rpc/dial.hpp> #include <viam/sdk/services/service.hpp> namespace viam { namespace sdk { -class Registry; - /// @defgroup Robot Classes related to a Robot representation. /// @class RobotClient client.hpp "robot/client.hpp" @@ -70,8 +68,7 @@ class RobotClient { /// @param address The address of the robot (IP address, URI, URL, etc.) /// @param options Options for connecting and refreshing. static std::shared_ptr<RobotClient> at_address(const std::string& address, - const Options& options, - Registry* registry); + const Options& options); /// @brief Creates a robot client connected to the robot at the provided local socket. /// @param address The local socket of the robot (a .sock file, etc.). @@ -79,8 +76,7 @@ class RobotClient { /// Creates a direct connection to the robot using the `unix://` scheme. /// Only useful for connecting to robots across Unix sockets. static std::shared_ptr<RobotClient> at_local_socket(const std::string& address, - const Options& options, - Registry* registry); + const Options& options); /// @brief Creates a robot client connected to the provided channel. /// @param channel The channel to connect with. @@ -88,11 +84,8 @@ class RobotClient { /// Connects directly to a pre-existing channel. A robot created this way must be /// `close()`d manually. static std::shared_ptr<RobotClient> with_channel(std::shared_ptr<ViamChannel> channel, - const Options& options, - Registry* registry); - - RobotClient(std::shared_ptr<ViamChannel> channel, Registry* registry); - + const Options& options); + RobotClient(std::shared_ptr<ViamChannel> channel); std::vector<Name> resource_names() const; /// @brief Lookup and return a `shared_ptr` to a resource. @@ -155,24 +148,17 @@ class RobotClient { private: Registry* registry_; - std::vector<std::shared_ptr<std::thread>> threads_; - std::atomic<bool> should_refresh_; unsigned int refresh_interval_; - std::shared_ptr<GrpcChannel> channel_; std::shared_ptr<ViamChannel> viam_channel_; bool should_close_channel_; - struct impl; std::unique_ptr<impl> impl_; - mutable std::mutex lock_; - std::vector<Name> resource_names_; ResourceManager resource_manager_; - void refresh_every(); }; diff --git a/src/viam/sdk/rpc/server.cpp b/src/viam/sdk/rpc/server.cpp index b2c46c695..9964abbac 100644 --- a/src/viam/sdk/rpc/server.cpp +++ b/src/viam/sdk/rpc/server.cpp @@ -15,11 +15,11 @@ namespace viam { namespace sdk { -Server::Server(const Registry* registry) : builder_(std::make_unique<grpc::ServerBuilder>()) { +Server::Server() : builder_(std::make_unique<grpc::ServerBuilder>()) { builder_->SetMaxReceiveMessageSize(kMaxMessageSize); builder_->SetMaxSendMessageSize(kMaxMessageSize); builder_->SetMaxMessageSize(kMaxMessageSize); - for (const auto& rr : registry->registered_resource_servers()) { + for (const auto& rr : Registry::get().registered_resource_servers()) { auto new_manager = std::make_shared<ResourceManager>(); auto server = rr.second->create_resource_server(new_manager, *this); managed_servers_.emplace(rr.first, std::move(server)); diff --git a/src/viam/sdk/rpc/server.hpp b/src/viam/sdk/rpc/server.hpp index 5f868b779..e735a6351 100644 --- a/src/viam/sdk/rpc/server.hpp +++ b/src/viam/sdk/rpc/server.hpp @@ -23,13 +23,11 @@ class TestServer; namespace sdk { -class Registry; - /// @class Server server.hpp "rpc/server.hpp" /// @brief Defines gRPC `Server` functionality. class Server { public: - Server(const Registry* registry); + Server(); ~Server(); /// @brief Starts the grpc server. Can only be called once. diff --git a/src/viam/sdk/tests/test_robot.cpp b/src/viam/sdk/tests/test_robot.cpp index e3bead0c9..2018ed36b 100644 --- a/src/viam/sdk/tests/test_robot.cpp +++ b/src/viam/sdk/tests/test_robot.cpp @@ -42,7 +42,7 @@ void robot_client_to_mocks_pipeline(F&& test_case) { rm->add(std::string("mock_generic"), generic::MockGenericComponent::get_mock_generic()); rm->add(std::string("mock_motor"), motor::MockMotor::get_mock_motor()); rm->add(std::string("mock_camera"), camera::MockCamera::get_mock_camera()); - auto server = std::make_shared<sdk::Server>(Instance::current().registry()); + auto server = std::make_shared<sdk::Server>(); MockRobotService service(rm, *server); server->start(); @@ -51,8 +51,7 @@ void robot_client_to_mocks_pipeline(F&& test_case) { auto test_server = TestServer(server); auto grpc_channel = test_server.grpc_in_process_channel(); auto viam_channel = std::make_shared<ViamChannel>(grpc_channel, "", nullptr); - auto client = RobotClient::with_channel( - viam_channel, Options(0, boost::none), Instance::current().registry()); + auto client = RobotClient::with_channel(viam_channel, Options(0, boost::none)); // Run the passed-in test case on the created stack and give access to the // created RobotClient and MockRobotService. @@ -63,7 +62,7 @@ void robot_client_to_mocks_pipeline(F&& test_case) { } BOOST_AUTO_TEST_CASE(test_registering_resources) { - auto& registry = *Instance::current().registry(); + auto& registry = Registry::get(); // To test with mock resources we need to be able to create them, which means registering // constructors. This tests that we register correctly. diff --git a/src/viam/sdk/tests/test_utils.hpp b/src/viam/sdk/tests/test_utils.hpp index 3de43aed8..26a51444e 100644 --- a/src/viam/sdk/tests/test_utils.hpp +++ b/src/viam/sdk/tests/test_utils.hpp @@ -51,7 +51,7 @@ class TestServer { // The passed in test_case function will have access to the created ResourceClient. template <typename ResourceType, typename F> void client_to_mock_pipeline(std::shared_ptr<Resource> mock, F&& test_case) { - auto server = std::make_shared<sdk::Server>(sdk::Instance::current().registry()); + auto server = std::make_shared<sdk::Server>(); // normally the high level server service (either robot or module) handles adding managed // resources, but in this case we must do it ourselves. @@ -63,9 +63,8 @@ void client_to_mock_pipeline(std::shared_ptr<Resource> mock, F&& test_case) { auto test_server = TestServer(server); auto grpc_channel = test_server.grpc_in_process_channel(); - auto resource_client = sdk::Instance::current() - .registry() - ->lookup_resource_client(API::get<ResourceType>()) + auto resource_client = sdk::Registry::get() + .lookup_resource_client(API::get<ResourceType>()) ->create_rpc_client(mock->name(), std::move(grpc_channel)); // Run the passed-in test case on the created stack and give access to the From 18d26c92c4a0b39dc785c9306a3fcd803c736f0b Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 27 Feb 2025 13:51:47 -0500 Subject: [PATCH 15/86] revert and adapt examples --- src/viam/examples/camera/example_camera.cpp | 6 ++++++ src/viam/examples/dial/example_dial.cpp | 5 +++++ src/viam/examples/dial_api_key/example_dial_api_key.cpp | 5 +++++ .../mlmodel/example_audio_classification_client.cpp | 5 +++++ src/viam/examples/modules/complex/client.cpp | 5 +++++ src/viam/examples/modules/complex/main.cpp | 9 +++++++-- .../examples/modules/complex/test_complex_module.cpp | 5 +++-- src/viam/examples/modules/simple/client.cpp | 3 +++ src/viam/examples/modules/simple/main.cpp | 3 +++ src/viam/examples/modules/tflite/main.cpp | 9 +++++++-- src/viam/examples/motor/example_motor.cpp | 6 ++++++ 11 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/viam/examples/camera/example_camera.cpp b/src/viam/examples/camera/example_camera.cpp index bc1b0ab9a..d1eb9b80c 100644 --- a/src/viam/examples/camera/example_camera.cpp +++ b/src/viam/examples/camera/example_camera.cpp @@ -3,6 +3,7 @@ #include <unistd.h> #include <vector> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/camera.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -13,6 +14,11 @@ int main() { using std::endl; namespace vs = ::viam::sdk; try { + // Every Viam C++ SDK program must have one and only one Instance object which is created + // before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + vs::Instance inst; + // If you want to connect to a remote robot, this should be the url of the robot // Ex: xxx.xxx.viam.cloud std::string robot_address("localhost:8080"); diff --git a/src/viam/examples/dial/example_dial.cpp b/src/viam/examples/dial/example_dial.cpp index efa783dfb..f39522c26 100644 --- a/src/viam/examples/dial/example_dial.cpp +++ b/src/viam/examples/dial/example_dial.cpp @@ -9,6 +9,7 @@ #include <boost/optional.hpp> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/generic.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -16,6 +17,10 @@ using namespace viam::sdk; int main() { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + Instance inst; + const char* uri = "<your robot URI here>"; DialOptions dial_options; std::string type = "<your authentication type>"; diff --git a/src/viam/examples/dial_api_key/example_dial_api_key.cpp b/src/viam/examples/dial_api_key/example_dial_api_key.cpp index 4c47beffe..b723e4227 100644 --- a/src/viam/examples/dial_api_key/example_dial_api_key.cpp +++ b/src/viam/examples/dial_api_key/example_dial_api_key.cpp @@ -10,6 +10,7 @@ #include <boost/optional.hpp> #include <boost/program_options.hpp> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -18,6 +19,10 @@ using namespace viam::sdk; namespace po = boost::program_options; int main(int argc, char* argv[]) { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + Instance inst; + po::options_description desc("Allowed options"); desc.add_options()("help", "List options and exit")( "uri", po::value<std::string>(), "URI of robot")( diff --git a/src/viam/examples/mlmodel/example_audio_classification_client.cpp b/src/viam/examples/mlmodel/example_audio_classification_client.cpp index 95e26f57c..6be570449 100644 --- a/src/viam/examples/mlmodel/example_audio_classification_client.cpp +++ b/src/viam/examples/mlmodel/example_audio_classification_client.cpp @@ -29,6 +29,7 @@ #include <boost/program_options.hpp> #include <boost/variant/get.hpp> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/services/mlmodel.hpp> @@ -78,6 +79,10 @@ constexpr char kRobotConfigTemplate[] = R"( } // namespace int main(int argc, char* argv[]) try { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + viam::sdk::Instance inst; + // Build up our command line options. The example operates in two // modes. In the "--generate" mode, it takes command line // parameters needed to satisfy the interpolation points in the diff --git a/src/viam/examples/modules/complex/client.cpp b/src/viam/examples/modules/complex/client.cpp index ac85c9f00..4c26f055f 100644 --- a/src/viam/examples/modules/complex/client.cpp +++ b/src/viam/examples/modules/complex/client.cpp @@ -11,6 +11,7 @@ #include <grpcpp/grpcpp.h> #include <grpcpp/support/status.h> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/motor.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -21,6 +22,10 @@ using namespace viam::sdk; int main() { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + Instance inst; + const char* uri = "http://localhost:8080/"; // replace with your URI if connecting securely DialOptions dial_options; dial_options.set_allow_insecure_downgrade(true); // set to false if connecting securely diff --git a/src/viam/examples/modules/complex/main.cpp b/src/viam/examples/modules/complex/main.cpp index da80453e6..c6a1e7532 100644 --- a/src/viam/examples/modules/complex/main.cpp +++ b/src/viam/examples/modules/complex/main.cpp @@ -5,6 +5,7 @@ #include <grpcpp/grpcpp.h> #include <grpcpp/server_context.h> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/base.hpp> #include <viam/sdk/components/component.hpp> #include <viam/sdk/config/resource.hpp> @@ -24,11 +25,15 @@ using namespace viam::sdk; int main(int argc, char** argv) { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + Instance inst; + Model mybase_model("viam", "base", "mybase"); // Make sure to explicity register resources with custom APIs. - Registry::get().register_resource_server<GizmoServer>(); - Registry::get().register_resource_server<SummationServer>(); + inst.registry()->register_resource_server<GizmoServer>(); + inst.registry()->register_resource_server<SummationServer>(); std::shared_ptr<ModelRegistration> mybase_mr = std::make_shared<ModelRegistration>( API::get<Base>(), diff --git a/src/viam/examples/modules/complex/test_complex_module.cpp b/src/viam/examples/modules/complex/test_complex_module.cpp index 14d68a8cf..3f4d4ee3d 100644 --- a/src/viam/examples/modules/complex/test_complex_module.cpp +++ b/src/viam/examples/modules/complex/test_complex_module.cpp @@ -24,8 +24,9 @@ using namespace viam::sdktests; struct RegisterGizmoAndSummationFixture { RegisterGizmoAndSummationFixture() { - Registry::get().register_resource<GizmoClient, GizmoServer>(); - Registry::get().register_resource<SummationClient, SummationServer>(); + auto* registry = Instance::current().registry(); + registry->register_resource<GizmoClient, GizmoServer>(); + registry->register_resource<SummationClient, SummationServer>(); } // Test teardown is a noop; diff --git a/src/viam/examples/modules/simple/client.cpp b/src/viam/examples/modules/simple/client.cpp index fcaab5eff..09e510636 100644 --- a/src/viam/examples/modules/simple/client.cpp +++ b/src/viam/examples/modules/simple/client.cpp @@ -2,6 +2,7 @@ #include <memory> #include <string> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/components/sensor.hpp> #include <viam/sdk/robot/client.hpp> @@ -10,6 +11,8 @@ using namespace viam::sdk; int main() { + Instance inst; + const char* uri = "http://localhost:8080/"; // replace with your URI if connecting securely DialOptions dial_options; dial_options.set_allow_insecure_downgrade(true); // set to false if connecting securely diff --git a/src/viam/examples/modules/simple/main.cpp b/src/viam/examples/modules/simple/main.cpp index cfd783f66..0df75464b 100644 --- a/src/viam/examples/modules/simple/main.cpp +++ b/src/viam/examples/modules/simple/main.cpp @@ -3,6 +3,7 @@ #include <sstream> #include <viam/sdk/common/exception.hpp> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/components/sensor.hpp> #include <viam/sdk/config/resource.hpp> @@ -75,6 +76,8 @@ ProtoStruct MySensor::get_readings(const ProtoStruct&) { } int main(int argc, char** argv) try { + Instance inst; + Model mysensor_model("viam", "sensor", "mysensor"); std::shared_ptr<ModelRegistration> mr = std::make_shared<ModelRegistration>( diff --git a/src/viam/examples/modules/tflite/main.cpp b/src/viam/examples/modules/tflite/main.cpp index 44cd8e284..e1c806354 100644 --- a/src/viam/examples/modules/tflite/main.cpp +++ b/src/viam/examples/modules/tflite/main.cpp @@ -23,6 +23,7 @@ #include <tensorflow/lite/c/c_api.h> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/components/component.hpp> #include <viam/sdk/config/resource.hpp> @@ -723,6 +724,10 @@ class MLModelServiceTFLite : public vsdk::MLModelService, }; int serve(const std::string& socket_path) try { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + vsdk::Instance inst; + // Create a new model registration for the service. auto module_registration = std::make_shared<vsdk::ModelRegistration>( // Identify that this resource offers the MLModelService API @@ -737,10 +742,10 @@ int serve(const std::string& socket_path) try { }); // Register the newly created registration with the Registry. - vsdk::Registry::register_model(module_registration); + inst.registry()->register_model(module_registration); // Construct the module service and tell it where to place the socket path. - auto module_service = std::make_shared<vsdk::ModuleService>(socket_path); + auto module_service = std::make_shared<vsdk::ModuleService>(socket_path, inst.registry()); // Add the server as providing the API and model declared in the // registration. diff --git a/src/viam/examples/motor/example_motor.cpp b/src/viam/examples/motor/example_motor.cpp index c4d8023d5..3d5a640ef 100644 --- a/src/viam/examples/motor/example_motor.cpp +++ b/src/viam/examples/motor/example_motor.cpp @@ -6,6 +6,7 @@ #include <string> #include <vector> +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/motor.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -27,6 +28,11 @@ int main() { namespace vs = ::viam::sdk; try { + // Every Viam C++ SDK program must have one and only one Instance object which is created + // before any other C++ SDK objects and stays alive until all Viam C++ SDK objects are + // destroyed. + vs::Instance inst; + // If you want to connect to a remote robot, this should be the url of the robot // Ex: xxx.xxx.viam.cloud std::string robot_address("localhost:8080"); From 60183237def4a3aff5c2163efd31ce86630b45c6 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 27 Feb 2025 14:26:16 -0500 Subject: [PATCH 16/86] make instance more of a black box --- src/viam/examples/modules/complex/main.cpp | 4 ++-- .../examples/modules/complex/test_complex_module.cpp | 6 +++--- src/viam/examples/modules/tflite/main.cpp | 2 +- src/viam/sdk/common/instance.cpp | 9 +-------- src/viam/sdk/common/instance.hpp | 6 ++---- src/viam/sdk/registry/registry.cpp | 4 ++-- src/viam/sdk/tests/mocks/mock_robot.cpp | 2 +- 7 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/viam/examples/modules/complex/main.cpp b/src/viam/examples/modules/complex/main.cpp index c6a1e7532..253e69d78 100644 --- a/src/viam/examples/modules/complex/main.cpp +++ b/src/viam/examples/modules/complex/main.cpp @@ -32,8 +32,8 @@ int main(int argc, char** argv) { Model mybase_model("viam", "base", "mybase"); // Make sure to explicity register resources with custom APIs. - inst.registry()->register_resource_server<GizmoServer>(); - inst.registry()->register_resource_server<SummationServer>(); + Registry::get().register_resource_server<GizmoServer>(); + Registry::get().register_resource_server<SummationServer>(); std::shared_ptr<ModelRegistration> mybase_mr = std::make_shared<ModelRegistration>( API::get<Base>(), diff --git a/src/viam/examples/modules/complex/test_complex_module.cpp b/src/viam/examples/modules/complex/test_complex_module.cpp index 3f4d4ee3d..4a178271f 100644 --- a/src/viam/examples/modules/complex/test_complex_module.cpp +++ b/src/viam/examples/modules/complex/test_complex_module.cpp @@ -24,9 +24,9 @@ using namespace viam::sdktests; struct RegisterGizmoAndSummationFixture { RegisterGizmoAndSummationFixture() { - auto* registry = Instance::current().registry(); - registry->register_resource<GizmoClient, GizmoServer>(); - registry->register_resource<SummationClient, SummationServer>(); + auto& registry = Registry::get(); + registry.register_resource<GizmoClient, GizmoServer>(); + registry.register_resource<SummationClient, SummationServer>(); } // Test teardown is a noop; diff --git a/src/viam/examples/modules/tflite/main.cpp b/src/viam/examples/modules/tflite/main.cpp index e1c806354..c1224266f 100644 --- a/src/viam/examples/modules/tflite/main.cpp +++ b/src/viam/examples/modules/tflite/main.cpp @@ -742,7 +742,7 @@ int serve(const std::string& socket_path) try { }); // Register the newly created registration with the Registry. - inst.registry()->register_model(module_registration); + Registry::get().register_model(module_registration); // Construct the module service and tell it where to place the socket path. auto module_service = std::make_shared<vsdk::ModuleService>(socket_path, inst.registry()); diff --git a/src/viam/sdk/common/instance.cpp b/src/viam/sdk/common/instance.cpp index c366ad6c6..bc52367f6 100644 --- a/src/viam/sdk/common/instance.cpp +++ b/src/viam/sdk/common/instance.cpp @@ -1,6 +1,7 @@ #include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/exception.hpp> +#include <viam/sdk/common/private/instance.hpp> #include <viam/sdk/registry/registry.hpp> #include <atomic> @@ -17,10 +18,6 @@ std::atomic<Instance*> current_instance{nullptr}; } // namespace -struct Instance::Impl { - Registry registry; -}; - Instance::Instance() { Instance* expected = nullptr; @@ -52,9 +49,5 @@ Instance& Instance::current() { return *current; } -Registry* Instance::registry() { - return &(impl_->registry); -} - } // namespace sdk } // namespace viam diff --git a/src/viam/sdk/common/instance.hpp b/src/viam/sdk/common/instance.hpp index c1ab0961f..1c97a2479 100644 --- a/src/viam/sdk/common/instance.hpp +++ b/src/viam/sdk/common/instance.hpp @@ -5,8 +5,6 @@ namespace viam { namespace sdk { -class Registry; - /// @brief Instance management for Viam C++ SDK applications. /// This is a single instance class which is responsible for global setup and teardown related to /// the SDK. An Instance must be constructed before doing anything else in a program, and it must @@ -19,9 +17,9 @@ class Instance { static Instance& current(); - Registry* registry(); - private: + friend class Registry; + struct Impl; std::unique_ptr<Impl> impl_; }; diff --git a/src/viam/sdk/registry/registry.cpp b/src/viam/sdk/registry/registry.cpp index 1ee9b5533..b1e8fb604 100644 --- a/src/viam/sdk/registry/registry.cpp +++ b/src/viam/sdk/registry/registry.cpp @@ -12,7 +12,7 @@ #include <grpcpp/ext/proto_server_reflection_plugin.h> #include <viam/sdk/common/exception.hpp> -#include <viam/sdk/common/instance.hpp> +#include <viam/sdk/common/private/instance.hpp> #include <viam/sdk/components/private/arm_client.hpp> #include <viam/sdk/components/private/arm_server.hpp> #include <viam/sdk/components/private/base_client.hpp> @@ -92,7 +92,7 @@ const Model& ModelRegistration::model() const { }; Registry& Registry::get() { - return *Instance::current().registry(); + return Instance::current().impl_->registry; } void Registry::register_model(std::shared_ptr<const ModelRegistration> resource) { diff --git a/src/viam/sdk/tests/mocks/mock_robot.cpp b/src/viam/sdk/tests/mocks/mock_robot.cpp index 5dc03fcc2..ce9a62884 100644 --- a/src/viam/sdk/tests/mocks/mock_robot.cpp +++ b/src/viam/sdk/tests/mocks/mock_robot.cpp @@ -26,7 +26,7 @@ std::vector<Name> registered_models_for_resource(const std::shared_ptr<Resource> std::string resource_type; std::string resource_subtype; std::vector<Name> resource_names; - for (const auto& kv : Instance::current().registry()->registered_models()) { + for (const auto& kv : Registry::get().registered_models()) { const std::shared_ptr<const ModelRegistration> reg = kv.second; if (reg->api() == resource->api()) { resource_type = reg->api().resource_type(); From 5535616d43a2fabe14e9c5a5a7d5b5718252a924 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 27 Feb 2025 14:40:39 -0500 Subject: [PATCH 17/86] add impl instance to git --- src/viam/sdk/common/private/instance.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/viam/sdk/common/private/instance.hpp diff --git a/src/viam/sdk/common/private/instance.hpp b/src/viam/sdk/common/private/instance.hpp new file mode 100644 index 000000000..b1728de8c --- /dev/null +++ b/src/viam/sdk/common/private/instance.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include <viam/sdk/common/instance.hpp> +#include <viam/sdk/registry/registry.hpp> + +namespace viam { +namespace sdk { + +struct Instance::Impl { + Registry registry; +}; + +} // namespace sdk +} // namespace viam From eeac195427f24641a37fceccaf4aa87fd4df6385 Mon Sep 17 00:00:00 2001 From: lia <167905060+lia-viam@users.noreply.github.com> Date: Mon, 3 Mar 2025 10:05:20 -0500 Subject: [PATCH 18/86] Add instance comment boilerplate Co-authored-by: Ethan <ethanrodkin@proton.me> --- src/viam/examples/modules/simple/client.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/viam/examples/modules/simple/client.cpp b/src/viam/examples/modules/simple/client.cpp index 09e510636..f08410336 100644 --- a/src/viam/examples/modules/simple/client.cpp +++ b/src/viam/examples/modules/simple/client.cpp @@ -11,6 +11,8 @@ using namespace viam::sdk; int main() { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. Instance inst; const char* uri = "http://localhost:8080/"; // replace with your URI if connecting securely From 7560f6d0c965939d5ae388bd49766aa268c19e67 Mon Sep 17 00:00:00 2001 From: lia <167905060+lia-viam@users.noreply.github.com> Date: Mon, 3 Mar 2025 10:05:49 -0500 Subject: [PATCH 19/86] Add instance comment boilerplate Co-authored-by: Ethan <ethanrodkin@proton.me> --- src/viam/examples/modules/simple/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/viam/examples/modules/simple/main.cpp b/src/viam/examples/modules/simple/main.cpp index 0df75464b..e85c2fe3a 100644 --- a/src/viam/examples/modules/simple/main.cpp +++ b/src/viam/examples/modules/simple/main.cpp @@ -76,6 +76,8 @@ ProtoStruct MySensor::get_readings(const ProtoStruct&) { } int main(int argc, char** argv) try { + // Every Viam C++ SDK program must have one and only one Instance object which is created before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. Instance inst; Model mysensor_model("viam", "sensor", "mysensor"); From af084037688853000bdf5284f4814c63cd645c3a Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 3 Mar 2025 13:18:52 -0500 Subject: [PATCH 20/86] connect robot client logging when parent of module service --- src/viam/sdk/CMakeLists.txt | 1 + src/viam/sdk/log/private/log_backend.cpp | 7 ++++ src/viam/sdk/log/private/log_backend.hpp | 31 ++++++++++++++++++ src/viam/sdk/module/service.cpp | 1 + src/viam/sdk/robot/client.cpp | 41 +++++++++++++++++++++++- src/viam/sdk/robot/client.hpp | 17 +++++++++- 6 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 src/viam/sdk/log/private/log_backend.cpp create mode 100644 src/viam/sdk/log/private/log_backend.hpp diff --git a/src/viam/sdk/CMakeLists.txt b/src/viam/sdk/CMakeLists.txt index 0ba964cc3..8970239dd 100644 --- a/src/viam/sdk/CMakeLists.txt +++ b/src/viam/sdk/CMakeLists.txt @@ -103,6 +103,7 @@ target_sources(viamsdk components/sensor.cpp components/servo.cpp config/resource.cpp + log/private/log_backend.cpp module/handler_map.cpp module/module.cpp module/service.cpp diff --git a/src/viam/sdk/log/private/log_backend.cpp b/src/viam/sdk/log/private/log_backend.cpp new file mode 100644 index 000000000..c7f3acf78 --- /dev/null +++ b/src/viam/sdk/log/private/log_backend.cpp @@ -0,0 +1,7 @@ +#include <viam/sdk/log/private/log_backend.hpp> + +namespace viam { +namespace sdk { +namespace impl {} +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/log/private/log_backend.hpp b/src/viam/sdk/log/private/log_backend.hpp new file mode 100644 index 000000000..de1ed7038 --- /dev/null +++ b/src/viam/sdk/log/private/log_backend.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include <boost/log/core/record_view.hpp> +#include <boost/log/sinks/basic_sink_backend.hpp> +#include <boost/log/sinks/sync_frontend.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <viam/sdk/robot/client.hpp> + +namespace viam { +namespace sdk { +namespace impl { + +struct LogBackend : boost::log::sinks::basic_sink_backend<boost::log::sinks::synchronized_feeding> { + LogBackend(RobotClient* p) : parent(p) {} + + void consume(const boost::log::record_view&); + + static auto create(RobotClient* p) { + auto backend = boost::make_shared<LogBackend>(p); + return boost::make_shared<boost::log::sinks::synchronous_sink<LogBackend>>(backend); + } + + RobotClient* parent; +}; + +using SinkType = boost::log::sinks::synchronous_sink<LogBackend>; + +} // namespace impl +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/module/service.cpp b/src/viam/sdk/module/service.cpp index d644b5420..ea3f5fccb 100644 --- a/src/viam/sdk/module/service.cpp +++ b/src/viam/sdk/module/service.cpp @@ -209,6 +209,7 @@ Dependencies ModuleService::get_dependencies_( std::shared_ptr<Resource> ModuleService::get_parent_resource_(const Name& name) { if (!parent_) { parent_ = RobotClient::at_local_socket(parent_addr_, {0, boost::none}); + parent_->connect_logging(); } return parent_->resource_by_name(name); diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index a8cb16c75..a20716a76 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -9,6 +9,7 @@ #include <unistd.h> #include <vector> +#include <boost/log/core/core.hpp> #include <boost/log/trivial.hpp> #include <grpcpp/channel.h> #include <grpcpp/client_context.h> @@ -24,6 +25,7 @@ #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/common/utils.hpp> #include <viam/sdk/components/component.hpp> +#include <viam/sdk/log/private/log_backend.hpp> #include <viam/sdk/registry/registry.hpp> #include <viam/sdk/resource/resource.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -84,9 +86,26 @@ bool operator==(const RobotClient::operation& lhs, const RobotClient::operation& struct RobotClient::impl { impl(std::unique_ptr<RobotService::Stub> stub) : stub_(std::move(stub)) {} + + ~impl() { + if (log_sink) { + boost::log::core::get()->remove_sink(log_sink); + } + } + std::unique_ptr<RobotService::Stub> stub_; + + boost::shared_ptr<viam::sdk::impl::SinkType> log_sink; }; +void RobotClient::connect_logging() { + auto& sink = impl_->log_sink; + if (!sink) { + sink = sdk::impl::LogBackend::create(this); + boost::log::core::get()->add_sink(sink); + } +} + RobotClient::~RobotClient() { if (should_close_channel_) { try { @@ -226,13 +245,33 @@ RobotClient::RobotClient(std::shared_ptr<ViamChannel> channel) channel_(channel->channel()), viam_channel_(std::move(channel)), should_close_channel_(false), - impl_(std::make_unique<impl>(RobotService::NewStub(channel_))) {} + impl_(std::make_unique<impl>(RobotService::NewStub(channel_), this)) {} std::vector<Name> RobotClient::resource_names() const { const std::lock_guard<std::mutex> lock(lock_); return resource_names_; } +void RobotClient::log( + const std::string& name, + const std::string& level, + const std::string& message, + std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> time) { + robot::v1::LogRequest req; + common::v1::LogEntry log; + + *log.mutable_logger_name() = name; + log.set_level(level); + *log.mutable_message() = message; + (void)time; + req.mutable_logs()->Add(std::move(log)); + + robot::v1::LogResponse resp; + ClientContext ctx; + const auto response = impl_->stub_->Log(ctx, req, &resp); + (void)response; +} + std::shared_ptr<RobotClient> RobotClient::with_channel(std::shared_ptr<ViamChannel> channel, const Options& options) { std::shared_ptr<RobotClient> robot = std::make_shared<RobotClient>(std::move(channel)); diff --git a/src/viam/sdk/robot/client.hpp b/src/viam/sdk/robot/client.hpp index 410abca28..473ecf5a9 100644 --- a/src/viam/sdk/robot/client.hpp +++ b/src/viam/sdk/robot/client.hpp @@ -85,7 +85,16 @@ class RobotClient { /// `close()`d manually. static std::shared_ptr<RobotClient> with_channel(std::shared_ptr<ViamChannel> channel, const Options& options); + RobotClient(std::shared_ptr<ViamChannel> channel); + + void log(const std::string& name, + const std::string& level, + const std::string& message, + std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> time); + + void connect_logging(); + std::vector<Name> resource_names() const; /// @brief Lookup and return a `shared_ptr` to a resource. @@ -147,19 +156,25 @@ class RobotClient { status get_machine_status() const; private: + void refresh_every(); + Registry* registry_; + std::vector<std::shared_ptr<std::thread>> threads_; std::atomic<bool> should_refresh_; unsigned int refresh_interval_; + std::shared_ptr<GrpcChannel> channel_; std::shared_ptr<ViamChannel> viam_channel_; bool should_close_channel_; + struct impl; std::unique_ptr<impl> impl_; + mutable std::mutex lock_; + std::vector<Name> resource_names_; ResourceManager resource_manager_; - void refresh_every(); }; } // namespace sdk From 4e25d35b30bfaa3fae2452576e23c32da9c57690 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 3 Mar 2025 14:52:30 -0500 Subject: [PATCH 21/86] remove old ctor arg --- src/viam/examples/modules/tflite/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/viam/examples/modules/tflite/main.cpp b/src/viam/examples/modules/tflite/main.cpp index c1224266f..65ca8c191 100644 --- a/src/viam/examples/modules/tflite/main.cpp +++ b/src/viam/examples/modules/tflite/main.cpp @@ -745,7 +745,7 @@ int serve(const std::string& socket_path) try { Registry::get().register_model(module_registration); // Construct the module service and tell it where to place the socket path. - auto module_service = std::make_shared<vsdk::ModuleService>(socket_path, inst.registry()); + auto module_service = std::make_shared<vsdk::ModuleService>(socket_path); // Add the server as providing the API and model declared in the // registration. From 55baa6c00d4d3de8eeaaeb2befb13423db23c143 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 3 Mar 2025 14:53:26 -0500 Subject: [PATCH 22/86] prohibit multi instance --- src/viam/sdk/common/instance.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/viam/sdk/common/instance.hpp b/src/viam/sdk/common/instance.hpp index 1c97a2479..64bb430c2 100644 --- a/src/viam/sdk/common/instance.hpp +++ b/src/viam/sdk/common/instance.hpp @@ -8,8 +8,8 @@ namespace sdk { /// @brief Instance management for Viam C++ SDK applications. /// This is a single instance class which is responsible for global setup and teardown related to /// the SDK. An Instance must be constructed before doing anything else in a program, and it must -/// remain alive in a valid state for the duration of the program. Creating multiple overlapping -/// Instance objects is an error. +/// remain alive in a valid state for the duration of the program. Creating multiple Instance +/// objects in the same program is an error. class Instance { public: Instance(); From 10cd711441b03ea12bea259ba27013d622a0a8a3 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 3 Mar 2025 14:54:54 -0500 Subject: [PATCH 23/86] remove initialized flag --- src/viam/sdk/registry/registry.cpp | 7 ------- src/viam/sdk/registry/registry.hpp | 3 ++- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/viam/sdk/registry/registry.cpp b/src/viam/sdk/registry/registry.cpp index b1e8fb604..15b1f118b 100644 --- a/src/viam/sdk/registry/registry.cpp +++ b/src/viam/sdk/registry/registry.cpp @@ -219,13 +219,6 @@ void Registry::register_resources() { } void Registry::initialize() { - const std::lock_guard<std::mutex> lock(lock_); - if (initialized_) { - BOOST_LOG_TRIVIAL(warning) - << "Attempted to initialize the Registry but it was already initialized."; - return; - } - initialized_ = true; register_resources(); grpc::reflection::InitProtoReflectionServerBuilderPlugin(); } diff --git a/src/viam/sdk/registry/registry.hpp b/src/viam/sdk/registry/registry.hpp index f09ee2d62..c1a5055a3 100644 --- a/src/viam/sdk/registry/registry.hpp +++ b/src/viam/sdk/registry/registry.hpp @@ -194,8 +194,9 @@ class Registry { void initialize(); mutable std::mutex lock_; - bool initialized_{false}; + std::unordered_map<std::string, std::shared_ptr<const ModelRegistration>> resources_; + std::unordered_map<API, std::shared_ptr<const ResourceClientRegistration>> client_apis_; std::unordered_map<API, std::shared_ptr<const ResourceServerRegistration>> server_apis_; From c74542296e2513e09281450fdb6e1452b72129a5 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 3 Mar 2025 14:55:54 -0500 Subject: [PATCH 24/86] meyers singleton registry --- src/viam/sdk/registry/registry.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/viam/sdk/registry/registry.cpp b/src/viam/sdk/registry/registry.cpp index 15b1f118b..e538d2ec2 100644 --- a/src/viam/sdk/registry/registry.cpp +++ b/src/viam/sdk/registry/registry.cpp @@ -92,7 +92,9 @@ const Model& ModelRegistration::model() const { }; Registry& Registry::get() { - return Instance::current().impl_->registry; + static Registry& result = Instance::current().impl_->registry; + + return result; } void Registry::register_model(std::shared_ptr<const ModelRegistration> resource) { From 75ab450a7fa122ff93e50ff9226ab9c49f003177 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:13:33 -0500 Subject: [PATCH 25/86] remove registry member and fix member spacing/ordering --- src/viam/sdk/module/service.cpp | 14 ++++++-------- src/viam/sdk/module/service.hpp | 2 -- src/viam/sdk/robot/client.cpp | 6 +++--- src/viam/sdk/robot/client.hpp | 9 +++++++-- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/viam/sdk/module/service.cpp b/src/viam/sdk/module/service.cpp index d644b5420..911be9bb3 100644 --- a/src/viam/sdk/module/service.cpp +++ b/src/viam/sdk/module/service.cpp @@ -57,7 +57,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { std::shared_ptr<Resource> res; const Dependencies deps = parent.get_dependencies_(&request->dependencies(), cfg.name()); const std::shared_ptr<const ModelRegistration> reg = - parent.registry_->lookup_model(cfg.api(), cfg.model()); + Registry::get().lookup_model(cfg.api(), cfg.model()); if (reg) { try { res = reg->construct_resource(deps, cfg); @@ -112,7 +112,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { } const std::shared_ptr<const ModelRegistration> reg = - parent.registry_->lookup_model(cfg.name()); + Registry::get().lookup_model(cfg.name()); if (reg) { try { const std::shared_ptr<Resource> res = reg->construct_resource(deps, cfg); @@ -132,7 +132,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { ResourceConfig cfg = from_proto(proto); const std::shared_ptr<const ModelRegistration> reg = - parent.registry_->lookup_model(cfg.api(), cfg.model()); + Registry::get().lookup_model(cfg.api(), cfg.model()); if (!reg) { return grpc::Status(grpc::UNKNOWN, "unable to validate resource " + cfg.resource_name().name() + @@ -215,9 +215,7 @@ std::shared_ptr<Resource> ModuleService::get_parent_resource_(const Name& name) } ModuleService::ModuleService(std::string addr) - : registry_(&Registry::get()), - module_(std::make_unique<Module>(std::move(addr))), - server_(std::make_unique<Server>()) { + : module_(std::make_unique<Module>(std::move(addr))), server_(std::make_unique<Server>()) { impl_ = std::make_unique<ServiceImpl>(*this); } @@ -234,7 +232,7 @@ ModuleService::ModuleService(int argc, set_logger_severity_from_args(argc, argv); for (auto&& mr : registrations) { - registry_->register_model(mr); + Registry::get().register_model(mr); add_model_from_registry(mr->api(), mr->model()); } } @@ -277,7 +275,7 @@ void ModuleService::add_model_from_registry_inlock_(API api, Model model, const std::lock_guard<std::mutex>&) { const std::shared_ptr<const ResourceServerRegistration> creator = - registry_->lookup_resource_server(api); + Registry::get().lookup_resource_server(api); std::string name; if (creator && creator->service_descriptor()) { name = creator->service_descriptor()->full_name(); diff --git a/src/viam/sdk/module/service.hpp b/src/viam/sdk/module/service.hpp index 95a7ad4f3..799ba1ab5 100644 --- a/src/viam/sdk/module/service.hpp +++ b/src/viam/sdk/module/service.hpp @@ -64,8 +64,6 @@ class ModuleService { std::string const& resource_name); std::shared_ptr<Resource> get_parent_resource_(const Name& name); - Registry* registry_; - std::mutex lock_; std::unique_ptr<Module> module_; std::shared_ptr<RobotClient> parent_; diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index a8cb16c75..6c2f0f0fe 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -178,7 +178,8 @@ void RobotClient::refresh() { // are being properly registered from name.subtype(), or update what we're // using for lookup const std::shared_ptr<const ResourceClientRegistration> rs = - registry_->lookup_resource_client({name.namespace_(), name.type(), name.subtype()}); + Registry::get().lookup_resource_client( + {name.namespace_(), name.type(), name.subtype()}); if (rs) { try { const std::shared_ptr<Resource> rpc_client = @@ -222,8 +223,7 @@ void RobotClient::refresh_every() { }; RobotClient::RobotClient(std::shared_ptr<ViamChannel> channel) - : registry_(&Registry::get()), - channel_(channel->channel()), + : channel_(channel->channel()), viam_channel_(std::move(channel)), should_close_channel_(false), impl_(std::make_unique<impl>(RobotService::NewStub(channel_))) {} diff --git a/src/viam/sdk/robot/client.hpp b/src/viam/sdk/robot/client.hpp index 410abca28..50fda612c 100644 --- a/src/viam/sdk/robot/client.hpp +++ b/src/viam/sdk/robot/client.hpp @@ -147,19 +147,24 @@ class RobotClient { status get_machine_status() const; private: - Registry* registry_; + void refresh_every(); + std::vector<std::shared_ptr<std::thread>> threads_; + std::atomic<bool> should_refresh_; unsigned int refresh_interval_; + std::shared_ptr<GrpcChannel> channel_; std::shared_ptr<ViamChannel> viam_channel_; bool should_close_channel_; + struct impl; std::unique_ptr<impl> impl_; + mutable std::mutex lock_; + std::vector<Name> resource_names_; ResourceManager resource_manager_; - void refresh_every(); }; } // namespace sdk From fc21c356bf455947c5cd8d3dd68b174b354a5766 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:19:14 -0500 Subject: [PATCH 26/86] remove unused include --- src/viam/sdk/tests/test_utils.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/viam/sdk/tests/test_utils.hpp b/src/viam/sdk/tests/test_utils.hpp index 26a51444e..11519a551 100644 --- a/src/viam/sdk/tests/test_utils.hpp +++ b/src/viam/sdk/tests/test_utils.hpp @@ -2,7 +2,6 @@ #include <grpcpp/grpcpp.h> -#include <viam/sdk/common/instance.hpp> #include <viam/sdk/config/resource.hpp> #include <viam/sdk/registry/registry.hpp> #include <viam/sdk/resource/resource.hpp> From 795578ce39af04ef0fdfc1d5e7a94ef179b94a64 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 4 Mar 2025 15:46:00 -0500 Subject: [PATCH 27/86] first attempt full logger machinery --- src/viam/sdk/CMakeLists.txt | 2 + src/viam/sdk/common/instance.cpp | 1 + src/viam/sdk/common/instance.hpp | 1 + src/viam/sdk/common/private/instance.hpp | 2 + src/viam/sdk/log/logger.cpp | 88 ++++++++++++++++++++++++ src/viam/sdk/log/logger.hpp | 58 ++++++++++++++++ src/viam/sdk/log/private/keywords.hpp | 18 +++++ src/viam/sdk/log/private/log_backend.cpp | 11 ++- src/viam/sdk/log/private/log_backend.hpp | 1 - src/viam/sdk/resource/resource.hpp | 6 +- src/viam/sdk/robot/client.cpp | 2 + 11 files changed, 186 insertions(+), 4 deletions(-) create mode 100644 src/viam/sdk/log/logger.cpp create mode 100644 src/viam/sdk/log/logger.hpp create mode 100644 src/viam/sdk/log/private/keywords.hpp diff --git a/src/viam/sdk/CMakeLists.txt b/src/viam/sdk/CMakeLists.txt index 8970239dd..efbd6d2fd 100644 --- a/src/viam/sdk/CMakeLists.txt +++ b/src/viam/sdk/CMakeLists.txt @@ -103,6 +103,7 @@ target_sources(viamsdk components/sensor.cpp components/servo.cpp config/resource.cpp + log/logger.cpp log/private/log_backend.cpp module/handler_map.cpp module/module.cpp @@ -171,6 +172,7 @@ target_sources(viamsdk ../../viam/sdk/components/sensor.hpp ../../viam/sdk/components/servo.hpp ../../viam/sdk/config/resource.hpp + ../../viam/sdk/log/logger.hpp ../../viam/sdk/module/handler_map.hpp ../../viam/sdk/module/module.hpp ../../viam/sdk/module/service.hpp diff --git a/src/viam/sdk/common/instance.cpp b/src/viam/sdk/common/instance.cpp index bc52367f6..54c20ae18 100644 --- a/src/viam/sdk/common/instance.cpp +++ b/src/viam/sdk/common/instance.cpp @@ -27,6 +27,7 @@ Instance::Instance() { impl_ = std::make_unique<Instance::Impl>(); impl_->registry.initialize(); + impl_->logger.init_logging(); } Instance::~Instance() { diff --git a/src/viam/sdk/common/instance.hpp b/src/viam/sdk/common/instance.hpp index 64bb430c2..4bec87110 100644 --- a/src/viam/sdk/common/instance.hpp +++ b/src/viam/sdk/common/instance.hpp @@ -19,6 +19,7 @@ class Instance { private: friend class Registry; + friend class Logger; struct Impl; std::unique_ptr<Impl> impl_; diff --git a/src/viam/sdk/common/private/instance.hpp b/src/viam/sdk/common/private/instance.hpp index b1728de8c..622cfe354 100644 --- a/src/viam/sdk/common/private/instance.hpp +++ b/src/viam/sdk/common/private/instance.hpp @@ -1,6 +1,7 @@ #pragma once #include <viam/sdk/common/instance.hpp> +#include <viam/sdk/log/logger.hpp> #include <viam/sdk/registry/registry.hpp> namespace viam { @@ -8,6 +9,7 @@ namespace sdk { struct Instance::Impl { Registry registry; + Logger logger; }; } // namespace sdk diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp new file mode 100644 index 000000000..046b1b9b0 --- /dev/null +++ b/src/viam/sdk/log/logger.cpp @@ -0,0 +1,88 @@ +#include <viam/sdk/log/logger.hpp> + +#include <iostream> + +#include <boost/log/attributes.hpp> +#include <boost/log/expressions.hpp> +#include <boost/log/expressions/formatters/date_time.hpp> +#include <boost/log/expressions/keyword.hpp> +#include <boost/log/support/date_time.hpp> +#include <boost/log/utility/setup/console.hpp> + +#include <viam/sdk/common/instance.hpp> +#include <viam/sdk/common/private/instance.hpp> +#include <viam/sdk/log/private/keywords.hpp> + +namespace viam { +namespace sdk { + +std::string to_string(log_level lvl) { + switch (lvl) { + case log_level::trace: + return "trace"; + case log_level::debug: + return "debug"; + case log_level::info: + return "info"; + case log_level::warning: + return "warning"; + case log_level::error: // fallthrough + case log_level::fatal: + return "error"; + default: + return std::to_string(static_cast<std::underlying_type_t<log_level>>(lvl)); + } +} + +std::ostream& operator<<(std::ostream& os, log_level lvl) { + os << to_string(lvl); + return os; +} + +std::string global_resource_name() { + return "Viam C++ SDK"; +} + +bool Logger::Filter::operator()(const boost::log::attribute_value_set& attrs) { + auto sev = attrs[attr_sev]; + if (!sev) { + return false; + } + + auto resource = attrs[attr_channel]; + if (resource) { + auto it = parent->resource_levels_.find(*resource); + if (it != parent->resource_levels_.end()) { + return *sev >= it->second; + } + } + + return *sev >= parent->global_level_; +} + +Logger& Logger::get() { + static Logger& result = Instance::current().impl_->logger; + + return result; +} + +void Logger::init_logging() { + sdk_logger_.channel(global_resource_name()); + + boost::log::formatter fmt = + boost::log::expressions::stream + << boost::log::expressions::format_date_time<boost::posix_time::ptime>( + "TimeStamp", "%Y--%m--%d %H:%M:%S") + << ": [" << attr_channel << "] <" << attr_sev << "> [" << attr_file << ":" << attr_line + << "]" << boost::log::expressions::smessage; + + boost::log::add_console_log( + std::cout, boost::log::keywords::filter = Filter{this}, boost::log::keywords::format = fmt); + + boost::shared_ptr<boost::log::core> core = boost::log::core::get(); + + core->add_global_attribute("TimeStamp", boost::log::attributes::local_clock()); +} + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/log/logger.hpp b/src/viam/sdk/log/logger.hpp new file mode 100644 index 000000000..0379eebfc --- /dev/null +++ b/src/viam/sdk/log/logger.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include <cstdint> + +#include <map> +#include <memory> +#include <ostream> + +#include <boost/log/sources/severity_channel_logger.hpp> + +namespace viam { +namespace sdk { + +enum class log_level : std::int8_t { + trace = -2, + debug = -1, + info = 0, // default value is info + warning = 1, + error = 2, + fatal = 3, +}; + +std::string to_string(log_level); + +std::ostream& operator<<(std::ostream&, log_level); + +using LogSource = boost::log::sources::severity_channel_logger_mt<log_level>; + +std::string global_resource_name(); + +class Logger { + public: + struct Filter { + Logger* parent; + + bool operator()(const boost::log::attribute_value_set&); + }; + + void set_global_log_level(log_level); + void set_resource_log_level(std::string resource, log_level); + + static Logger& get(); + + private: + friend class Instance; + Logger() = default; + + void init_logging(); + + LogSource sdk_logger_; + + log_level global_level_{log_level::info}; + + std::map<std::string, log_level> resource_levels_; +}; + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/log/private/keywords.hpp b/src/viam/sdk/log/private/keywords.hpp new file mode 100644 index 000000000..4a5c53d87 --- /dev/null +++ b/src/viam/sdk/log/private/keywords.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include <boost/log/attributes/clock.hpp> +#include <boost/log/expressions/keyword.hpp> + +namespace viam { +namespace sdk { + +BOOST_LOG_ATTRIBUTE_KEYWORD(attr_channel, "Channel", std::string); +BOOST_LOG_ATTRIBUTE_KEYWORD(attr_sev, "Severity", viam::sdk::log_level); +BOOST_LOG_ATTRIBUTE_KEYWORD(attr_file, "file", const char*); +BOOST_LOG_ATTRIBUTE_KEYWORD(attr_line, "line", unsigned int); +BOOST_LOG_ATTRIBUTE_KEYWORD(attr_time, + "TimeStamp", + boost::log::attributes::local_clock::value_type); + +} // namespace sdk +} // namespace viam diff --git a/src/viam/sdk/log/private/log_backend.cpp b/src/viam/sdk/log/private/log_backend.cpp index d7eda691d..ca104cec7 100644 --- a/src/viam/sdk/log/private/log_backend.cpp +++ b/src/viam/sdk/log/private/log_backend.cpp @@ -1,10 +1,19 @@ #include <viam/sdk/log/private/log_backend.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <viam/sdk/log/private/keywords.hpp> + namespace viam { namespace sdk { namespace impl { -void LogBackend::consume(const boost::log::record_view& rec) {} +void LogBackend::consume(const boost::log::record_view& rec) { + // auto time = *rec[attr_time]; + + parent->log( + *rec[attr_channel], to_string(*rec[attr_sev]), *rec[boost::log::expressions::smessage], {}); +} boost::shared_ptr<SinkType> LogBackend::create(RobotClient* p) { auto backend = boost::make_shared<LogBackend>(p); diff --git a/src/viam/sdk/log/private/log_backend.hpp b/src/viam/sdk/log/private/log_backend.hpp index 62ade1c14..8bb2dc4cb 100644 --- a/src/viam/sdk/log/private/log_backend.hpp +++ b/src/viam/sdk/log/private/log_backend.hpp @@ -3,7 +3,6 @@ #include <boost/log/core/record_view.hpp> #include <boost/log/sinks/basic_sink_backend.hpp> #include <boost/log/sinks/sync_frontend.hpp> -#include <boost/smart_ptr/make_shared.hpp> #include <viam/sdk/robot/client.hpp> diff --git a/src/viam/sdk/resource/resource.hpp b/src/viam/sdk/resource/resource.hpp index d61e5eb04..918a988f0 100644 --- a/src/viam/sdk/resource/resource.hpp +++ b/src/viam/sdk/resource/resource.hpp @@ -2,18 +2,20 @@ #include <unordered_map> -#include <boost/log/sources/severity_channel_logger.hpp> #include <boost/log/trivial.hpp> #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/config/resource.hpp> +#include <viam/sdk/log/logger.hpp> #include <viam/sdk/resource/resource_api.hpp> namespace viam { namespace sdk { class Resource; + using Dependencies = std::unordered_map<Name, std::shared_ptr<Resource>>; + class Resource { public: virtual ~Resource(); @@ -34,7 +36,7 @@ class Resource { protected: Name get_resource_name(const std::string& type) const; - boost::log::sources::severity_channel_logger_mt<boost::log::trivial::severity_level> logger_; + LogSource logger_; }; template <> diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index 32e7a665a..2ec71752f 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -102,6 +102,8 @@ void RobotClient::connect_logging() { auto& sink = impl_->log_sink; if (!sink) { sink = sdk::impl::LogBackend::create(this); + sink->set_filter(Logger::Filter{&Logger::get()}); + boost::log::core::get()->add_sink(sink); } } From 1b88d1c084f838d133c9efa7045a550ee61f5656 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 7 Mar 2025 13:42:50 -0500 Subject: [PATCH 28/86] update log to have keywords in header --- src/viam/sdk/log/logger.cpp | 41 ++++++++++++++++------ src/viam/sdk/log/logger.hpp | 44 ++++++++++++++++++++++-- src/viam/sdk/log/private/keywords.hpp | 18 ---------- src/viam/sdk/log/private/log_backend.cpp | 18 +++++++--- 4 files changed, 87 insertions(+), 34 deletions(-) delete mode 100644 src/viam/sdk/log/private/keywords.hpp diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index 046b1b9b0..d3046e82a 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -2,6 +2,7 @@ #include <iostream> +#include <boost/core/null_deleter.hpp> #include <boost/log/attributes.hpp> #include <boost/log/expressions.hpp> #include <boost/log/expressions/formatters/date_time.hpp> @@ -11,7 +12,6 @@ #include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/private/instance.hpp> -#include <viam/sdk/log/private/keywords.hpp> namespace viam { namespace sdk { @@ -24,7 +24,7 @@ std::string to_string(log_level lvl) { return "debug"; case log_level::info: return "info"; - case log_level::warning: + case log_level::warn: return "warning"; case log_level::error: // fallthrough case log_level::fatal: @@ -44,12 +44,12 @@ std::string global_resource_name() { } bool Logger::Filter::operator()(const boost::log::attribute_value_set& attrs) { - auto sev = attrs[attr_sev]; + auto sev = attrs[attr_sev_type{}]; if (!sev) { return false; } - auto resource = attrs[attr_channel]; + auto resource = attrs[attr_channel_type{}]; if (resource) { auto it = parent->resource_levels_.find(*resource); if (it != parent->resource_levels_.end()) { @@ -66,22 +66,43 @@ Logger& Logger::get() { return result; } +void Logger::set_global_log_level(log_level lvl) { + global_level_ = lvl; +} + +void Logger::set_global_log_level(int argc, char** argv) { + if (argc >= 3 && strcmp(argv[2], "--log-level=debug") == 0) { + set_global_log_level(log_level::debug); + } +} + void Logger::init_logging() { sdk_logger_.channel(global_resource_name()); + boost::log::core::get()->add_global_attribute("TimeStamp", + boost::log::attributes::local_clock()); boost::log::formatter fmt = boost::log::expressions::stream << boost::log::expressions::format_date_time<boost::posix_time::ptime>( "TimeStamp", "%Y--%m--%d %H:%M:%S") - << ": [" << attr_channel << "] <" << attr_sev << "> [" << attr_file << ":" << attr_line - << "]" << boost::log::expressions::smessage; + << ": [" << attr_channel_type{} << "] <" << attr_sev_type{} << "> [" << attr_file_type{} + << ":" << attr_line_type{} << "] " << boost::log::expressions::smessage; + + auto backend = boost::make_shared<boost::log::sinks::text_ostream_backend>(); + backend->add_stream(boost::shared_ptr<std::ostream>(&std::cout, boost::null_deleter())); + backend->auto_flush(true); - boost::log::add_console_log( - std::cout, boost::log::keywords::filter = Filter{this}, boost::log::keywords::format = fmt); + console_sink_ = boost::make_shared< + boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend>>(backend); - boost::shared_ptr<boost::log::core> core = boost::log::core::get(); + console_sink_->set_filter(Filter{this}); + console_sink_->set_formatter(fmt); + + boost::log::core::get()->add_sink(console_sink_); +} - core->add_global_attribute("TimeStamp", boost::log::attributes::local_clock()); +void Logger::disable_console_logging() { + boost::log::core::get()->remove_sink(console_sink_); } } // namespace sdk diff --git a/src/viam/sdk/log/logger.hpp b/src/viam/sdk/log/logger.hpp index 0379eebfc..b860631f8 100644 --- a/src/viam/sdk/log/logger.hpp +++ b/src/viam/sdk/log/logger.hpp @@ -6,7 +6,12 @@ #include <memory> #include <ostream> +#include <boost/log/attributes/clock.hpp> +#include <boost/log/expressions/keyword.hpp> +#include <boost/log/sinks/sync_frontend.hpp> +#include <boost/log/sinks/text_ostream_backend.hpp> #include <boost/log/sources/severity_channel_logger.hpp> +#include <boost/log/utility/manipulators/add_value.hpp> namespace viam { namespace sdk { @@ -15,7 +20,7 @@ enum class log_level : std::int8_t { trace = -2, debug = -1, info = 0, // default value is info - warning = 1, + warn = 1, error = 2, fatal = 3, }; @@ -36,23 +41,58 @@ class Logger { bool operator()(const boost::log::attribute_value_set&); }; + static Logger& get(); + void set_global_log_level(log_level); + + /// @brief Set the SDK logger severity from a command line argument vector. + /// + /// Sets the boost trivial logger's severity to debug if "--log-level=debug" is the + /// the third argument. Sets severity to info otherwise. Useful for module + /// implementations. See LogLevel documentation in the RDK for more information on + /// how to start modules with a "log-level" commandline argument. + void set_global_log_level(int argc, char** argv); + void set_resource_log_level(std::string resource, log_level); - static Logger& get(); + LogSource& logger() { + return sdk_logger_; + } private: + friend class RobotClient; friend class Instance; Logger() = default; void init_logging(); + void disable_console_logging(); LogSource sdk_logger_; + boost::shared_ptr<boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend>> + console_sink_; log_level global_level_{log_level::info}; std::map<std::string, log_level> resource_levels_; }; +BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_channel, "Channel", std::string); +BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_sev, "Severity", viam::sdk::log_level); +BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_file, "file", const char*); +BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_line, "line", unsigned int); +BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_time, + "TimeStamp", + boost::log::attributes::local_clock::value_type); + +// Logging macro for general SDK logs +#define VIAM_LOG_IMPL(lg, level) \ + BOOST_LOG_SEV((lg), ::viam::sdk::log_level::level) \ + << ::boost::log::add_value(::viam::sdk::attr_file_type{}, __FILE__) \ + << ::boost::log::add_value(::viam::sdk::attr_line_type{}, __LINE__) + +#define VIAM_LOG(level) VIAM_LOG_IMPL(::viam::sdk::Logger::get().logger(), level) + +#define VIAM_RESOURCE_LOG(level) VIAM_LOG_IMPL(this->logger_, level) + } // namespace sdk } // namespace viam diff --git a/src/viam/sdk/log/private/keywords.hpp b/src/viam/sdk/log/private/keywords.hpp deleted file mode 100644 index 4a5c53d87..000000000 --- a/src/viam/sdk/log/private/keywords.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include <boost/log/attributes/clock.hpp> -#include <boost/log/expressions/keyword.hpp> - -namespace viam { -namespace sdk { - -BOOST_LOG_ATTRIBUTE_KEYWORD(attr_channel, "Channel", std::string); -BOOST_LOG_ATTRIBUTE_KEYWORD(attr_sev, "Severity", viam::sdk::log_level); -BOOST_LOG_ATTRIBUTE_KEYWORD(attr_file, "file", const char*); -BOOST_LOG_ATTRIBUTE_KEYWORD(attr_line, "line", unsigned int); -BOOST_LOG_ATTRIBUTE_KEYWORD(attr_time, - "TimeStamp", - boost::log::attributes::local_clock::value_type); - -} // namespace sdk -} // namespace viam diff --git a/src/viam/sdk/log/private/log_backend.cpp b/src/viam/sdk/log/private/log_backend.cpp index ca104cec7..1b0ab08e0 100644 --- a/src/viam/sdk/log/private/log_backend.cpp +++ b/src/viam/sdk/log/private/log_backend.cpp @@ -1,5 +1,6 @@ #include <viam/sdk/log/private/log_backend.hpp> +#include <boost/date_time/posix_time/conversion.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <viam/sdk/log/private/keywords.hpp> @@ -8,11 +9,20 @@ namespace viam { namespace sdk { namespace impl { -void LogBackend::consume(const boost::log::record_view& rec) { - // auto time = *rec[attr_time]; +time_pt ptime_convert(const boost::posix_time::ptime& from) { + boost::posix_time::time_duration const time_since_epoch = + from - boost::posix_time::from_time_t(0); + time_pt t = std::chrono::system_clock::from_time_t(time_since_epoch.total_seconds()); + long nsec = + time_since_epoch.fractional_seconds() * (1000000000 / time_since_epoch.ticks_per_second()); + return t + std::chrono::nanoseconds(nsec); +} - parent->log( - *rec[attr_channel], to_string(*rec[attr_sev]), *rec[boost::log::expressions::smessage], {}); +void LogBackend::consume(const boost::log::record_view& rec) { + parent->log(*rec[attr_channel_type{}], + to_string(*rec[attr_sev_type{}]), + *rec[boost::log::expressions::smessage], + ptime_convert(*rec[attr_time_type{}])); } boost::shared_ptr<SinkType> LogBackend::create(RobotClient* p) { From 5eb243b72ca5d1eb07cb90d808ba286f53552219 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 7 Mar 2025 13:45:07 -0500 Subject: [PATCH 29/86] init grpc logging in module service impl ready, and disable console logging --- src/viam/sdk/module/service.cpp | 19 +++++++++------ src/viam/sdk/module/service.hpp | 4 ++++ src/viam/sdk/robot/client.cpp | 41 ++++++++++++++++----------------- src/viam/sdk/robot/client.hpp | 2 +- 4 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/viam/sdk/module/service.cpp b/src/viam/sdk/module/service.cpp index 0d9c08aab..5acabe126 100644 --- a/src/viam/sdk/module/service.cpp +++ b/src/viam/sdk/module/service.cpp @@ -182,7 +182,12 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { const std::lock_guard<std::mutex> lock(parent.lock_); const viam::module::v1::HandlerMap hm = to_proto(parent.module_->handles()); *response->mutable_handlermap() = hm; - parent.parent_addr_ = request->parent_address(); + auto new_parent_addr = request->parent_address(); + if (parent.parent_addr_ != new_parent_addr) { + parent.parent_addr_ = std::move(new_parent_addr); + parent.parent_ = RobotClient::at_local_socket(parent.parent_addr_, {0, boost::none}); + parent.parent_->connect_logging(); + } response->set_ready(parent.module_->ready()); return grpc::Status(); } @@ -208,6 +213,7 @@ Dependencies ModuleService::get_dependencies_( std::shared_ptr<Resource> ModuleService::get_parent_resource_(const Name& name) { if (!parent_) { + // LS: I think maybe this is never hit parent_ = RobotClient::at_local_socket(parent_addr_, {0, boost::none}); parent_->connect_logging(); } @@ -230,7 +236,7 @@ ModuleService::ModuleService(int argc, } return argv[1]; }()) { - set_logger_severity_from_args(argc, argv); + Logger::get().set_global_log_level(argc, argv); for (auto&& mr : registrations) { Registry::get().register_model(mr); @@ -240,14 +246,14 @@ ModuleService::ModuleService(int argc, ModuleService::~ModuleService() { // TODO(RSDK-5509): Run registered cleanup functions here. - BOOST_LOG_TRIVIAL(info) << "Shutting down gracefully."; + VIAM_LOG(info) << "Shutting down gracefully."; server_->shutdown(); if (parent_) { try { parent_->close(); } catch (const std::exception& exc) { - BOOST_LOG_TRIVIAL(error) << exc.what(); + VIAM_LOG(error) << exc.what(); } } } @@ -265,9 +271,8 @@ void ModuleService::serve() { module_->set_ready(); server_->start(); - BOOST_LOG_TRIVIAL(info) << "Module listening on " << module_->addr(); - BOOST_LOG_TRIVIAL(info) << "Module handles the following API/model pairs:\n" - << module_->handles(); + VIAM_LOG(info) << "Module listening on " << module_->addr(); + VIAM_LOG(info) << "Module handles the following API/model pairs:\n" << module_->handles(); signal_manager_.wait(); } diff --git a/src/viam/sdk/module/service.hpp b/src/viam/sdk/module/service.hpp index 799ba1ab5..714d55051 100644 --- a/src/viam/sdk/module/service.hpp +++ b/src/viam/sdk/module/service.hpp @@ -65,10 +65,14 @@ class ModuleService { std::shared_ptr<Resource> get_parent_resource_(const Name& name); std::mutex lock_; + std::unique_ptr<Module> module_; + std::shared_ptr<RobotClient> parent_; std::string parent_addr_; + std::unique_ptr<Server> server_; + SignalManager signal_manager_; std::unique_ptr<ServiceImpl> impl_; diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index 2ec71752f..3e21adfa4 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -104,6 +104,7 @@ void RobotClient::connect_logging() { sink = sdk::impl::LogBackend::create(this); sink->set_filter(Logger::Filter{&Logger::get()}); + Logger::get().disable_console_logging(); boost::log::core::get()->add_sink(sink); } } @@ -113,9 +114,9 @@ RobotClient::~RobotClient() { try { this->close(); } catch (const std::exception& e) { - BOOST_LOG_TRIVIAL(error) << "Received err while closing RobotClient: " << e.what(); + VIAM_LOG(error) << "Received err while closing RobotClient: " << e.what(); } catch (...) { - BOOST_LOG_TRIVIAL(error) << "Received unknown err while closing RobotClient"; + VIAM_LOG(error) << "Received unknown err while closing RobotClient"; } } } @@ -142,7 +143,7 @@ std::vector<RobotClient::operation> RobotClient::get_operations() { grpc::Status const response = impl_->stub_->GetOperations(ctx, req, &resp); if (is_error_response(response)) { - BOOST_LOG_TRIVIAL(error) << "Error getting operations: " << response.error_message(); + VIAM_LOG(error) << "Error getting operations: " << response.error_message(); } for (int i = 0; i < resp.operations().size(); ++i) { @@ -160,7 +161,7 @@ void RobotClient::cancel_operation(std::string id) { req.set_id(id); const grpc::Status response = impl_->stub_->CancelOperation(ctx, req, &resp); if (is_error_response(response)) { - BOOST_LOG_TRIVIAL(error) << "Error canceling operation with id " << id; + VIAM_LOG(error) << "Error canceling operation with id " << id; } } @@ -173,7 +174,7 @@ void RobotClient::block_for_operation(std::string id) { const grpc::Status response = impl_->stub_->BlockForOperation(ctx, req, &resp); if (is_error_response(response)) { - BOOST_LOG_TRIVIAL(error) << "Error blocking for operation with id " << id; + VIAM_LOG(error) << "Error blocking for operation with id " << id; } } @@ -184,7 +185,7 @@ void RobotClient::refresh() { const grpc::Status response = impl_->stub_->ResourceNames(ctx, req, &resp); if (is_error_response(response)) { - BOOST_LOG_TRIVIAL(error) << "Error getting resource names: " << response.error_message(); + VIAM_LOG(error) << "Error getting resource names: " << response.error_message(); } std::unordered_map<Name, std::shared_ptr<Resource>> new_resources; @@ -208,8 +209,8 @@ void RobotClient::refresh() { const Name name_({name.namespace_(), name.type(), name.subtype()}, "", name.name()); new_resources.emplace(name_, rpc_client); } catch (const std::exception& exc) { - BOOST_LOG_TRIVIAL(debug) - << "Error registering component " << name.subtype() << ": " << exc.what(); + VIAM_LOG(debug) << "Error registering component " << name.subtype() << ": " + << exc.what(); } } } @@ -254,18 +255,17 @@ std::vector<Name> RobotClient::resource_names() const { return resource_names_; } -void RobotClient::log( - const std::string& name, - const std::string& level, - const std::string& message, - std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> time) { +void RobotClient::log(const std::string& name, + const std::string& level, + const std::string& message, + time_pt time) { robot::v1::LogRequest req; common::v1::LogEntry log; *log.mutable_logger_name() = name; log.set_level(level); *log.mutable_message() = message; - (void)time; + *log.mutable_time() = to_proto(time); req.mutable_logs()->Add(std::move(log)); robot::v1::LogResponse resp; @@ -326,8 +326,7 @@ std::vector<RobotClient::frame_system_config> RobotClient::get_frame_system_conf const grpc::Status response = impl_->stub_->FrameSystemConfig(ctx, req, &resp); if (is_error_response(response)) { - BOOST_LOG_TRIVIAL(error) << "Error getting frame system config: " - << response.error_message(); + VIAM_LOG(error) << "Error getting frame system config: " << response.error_message(); } const RepeatedPtrField<FrameSystemConfig> configs = resp.frame_system_configs(); @@ -355,7 +354,7 @@ pose_in_frame RobotClient::transform_pose( const grpc::Status response = impl_->stub_->TransformPose(ctx, req, &resp); if (is_error_response(response)) { - BOOST_LOG_TRIVIAL(error) << "Error getting PoseInFrame: " << response.error_message(); + VIAM_LOG(error) << "Error getting PoseInFrame: " << response.error_message(); } return from_proto(resp.pose()); @@ -390,8 +389,8 @@ void RobotClient::stop_all(const std::unordered_map<Name, ProtoStruct>& extra) { } const grpc::Status response = impl_->stub_->StopAll(ctx, req, &resp); if (is_error_response(response)) { - BOOST_LOG_TRIVIAL(error) << "Error stopping all: " << response.error_message() - << response.error_details(); + VIAM_LOG(error) << "Error stopping all: " << response.error_message() + << response.error_details(); } } @@ -419,8 +418,8 @@ RobotClient::status RobotClient::get_machine_status() const { const grpc::Status response = impl_->stub_->GetMachineStatus(ctx, req, &resp); if (is_error_response(response)) { - BOOST_LOG_TRIVIAL(error) << "Error getting machine status: " << response.error_message() - << response.error_details(); + VIAM_LOG(error) << "Error getting machine status: " << response.error_message() + << response.error_details(); } switch (resp.state()) { case robot::v1::GetMachineStatusResponse_State_STATE_INITIALIZING: diff --git a/src/viam/sdk/robot/client.hpp b/src/viam/sdk/robot/client.hpp index a818dcca5..e60eb0edc 100644 --- a/src/viam/sdk/robot/client.hpp +++ b/src/viam/sdk/robot/client.hpp @@ -91,7 +91,7 @@ class RobotClient { void log(const std::string& name, const std::string& level, const std::string& message, - std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> time); + time_pt time); void connect_logging(); From 6e311bc253d709fee7895e6fe2532a29df546a4f Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 7 Mar 2025 13:45:26 -0500 Subject: [PATCH 30/86] remove set severity from args --- src/viam/sdk/common/utils.cpp | 9 --------- src/viam/sdk/common/utils.hpp | 10 ---------- 2 files changed, 19 deletions(-) diff --git a/src/viam/sdk/common/utils.cpp b/src/viam/sdk/common/utils.cpp index 5825c2e7f..5b1134fec 100644 --- a/src/viam/sdk/common/utils.cpp +++ b/src/viam/sdk/common/utils.cpp @@ -96,15 +96,6 @@ std::string bytes_to_string(const std::vector<unsigned char>& b) { return img_string; } -void set_logger_severity_from_args(int argc, char** argv) { - if (argc >= 3 && strcmp(argv[2], "--log-level=debug") == 0) { - boost::log::core::get()->set_filter(boost::log::trivial::severity >= - boost::log::trivial::debug); - return; - } - boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::info); -} - std::string random_debug_key() { static const char alphanum[] = "abcdefghijklmnopqrstuvwxyz"; static std::default_random_engine generator( diff --git a/src/viam/sdk/common/utils.hpp b/src/viam/sdk/common/utils.hpp index f5067de55..51e360042 100644 --- a/src/viam/sdk/common/utils.hpp +++ b/src/viam/sdk/common/utils.hpp @@ -110,16 +110,6 @@ ProtoStruct with_debug_entry(ProtoStruct&& map, std::string debug_key); /// @returns the new ProtoStruct ProtoStruct with_debug_entry(ProtoStruct&& map); -/// @brief Set the boost trivial logger's severity depending on args. -/// @param argc The number of args. -/// @param argv The commandline arguments to parse. -/// -/// Sets the boost trivial logger's severity to debug if "--log-level=debug" is the -/// the third argument. Sets severity to info otherwise. Useful for module -/// implementations. See LogLevel documentation in the RDK for more information on -/// how to start modules with a "log-level" commandline argument. -void set_logger_severity_from_args(int argc, char** argv); - /// @brief Used in modular filter components to get the 'fromDataManagement' value from an extra /// ProtoStruct. /// @param extra The extra ProtoStruct. From f84fe6e4ea6c3dcb79753e13121465afa3cbcc88 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 7 Mar 2025 13:45:58 -0500 Subject: [PATCH 31/86] update boost_log_trivial invocations --- src/viam/sdk/common/client_helper.cpp | 7 +++---- src/viam/sdk/module/handler_map.cpp | 2 +- src/viam/sdk/resource/resource_manager.cpp | 9 ++++----- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/viam/sdk/common/client_helper.cpp b/src/viam/sdk/common/client_helper.cpp index b05bb37fe..24eeb7db8 100644 --- a/src/viam/sdk/common/client_helper.cpp +++ b/src/viam/sdk/common/client_helper.cpp @@ -5,9 +5,8 @@ #include <grpcpp/client_context.h> #include <grpcpp/support/status.h> -#include <boost/log/trivial.hpp> - #include <viam/sdk/common/private/version_metadata.hpp> +#include <viam/sdk/log/logger.hpp> namespace viam { namespace sdk { @@ -15,8 +14,8 @@ namespace sdk { namespace client_helper_details { [[noreturn]] void errorHandlerReturnedUnexpectedly(const ::grpc::Status* status) noexcept { - BOOST_LOG_TRIVIAL(fatal) << "ClientHelper error handler callback returned instead of throwing: " - << status->error_message() << '(' << status->error_details() << ')'; + VIAM_LOG(fatal) << "ClientHelper error handler callback returned instead of throwing: " + << status->error_message() << '(' << status->error_details() << ')'; std::abort(); } diff --git a/src/viam/sdk/module/handler_map.cpp b/src/viam/sdk/module/handler_map.cpp index 4d2ba34bf..b538ad734 100644 --- a/src/viam/sdk/module/handler_map.cpp +++ b/src/viam/sdk/module/handler_map.cpp @@ -66,7 +66,7 @@ HandlerMap_ from_proto_impl<module::v1::HandlerMap>::operator()( try { hm.add_model(Model::from_str(mod), handle); } catch (const std::exception& ex) { - BOOST_LOG_TRIVIAL(error) << "Error " << ex.what() << " processing model " + mod; + VIAM_LOG(error) << "Error " << ex.what() << " processing model " + mod; } } } diff --git a/src/viam/sdk/resource/resource_manager.cpp b/src/viam/sdk/resource/resource_manager.cpp index 8f2940c5f..d67e93972 100644 --- a/src/viam/sdk/resource/resource_manager.cpp +++ b/src/viam/sdk/resource/resource_manager.cpp @@ -52,7 +52,7 @@ void ResourceManager::replace_all( try { do_add(resource.first, resource.second); } catch (std::exception& exc) { - BOOST_LOG_TRIVIAL(error) << "Error replacing all resources" << exc.what(); + VIAM_LOG(error) << "Error replacing all resources" << exc.what(); return; } } @@ -97,7 +97,7 @@ void ResourceManager::add(const Name& name, std::shared_ptr<Resource> resource) try { do_add(name, std::move(resource)); } catch (std::exception& exc) { - BOOST_LOG_TRIVIAL(error) << "Error adding resource to subtype service: " << exc.what(); + VIAM_LOG(error) << "Error adding resource to subtype service: " << exc.what(); } }; @@ -134,7 +134,7 @@ void ResourceManager::remove(const Name& name) { try { do_remove(name); } catch (std::exception& exc) { - BOOST_LOG_TRIVIAL(error) << "unable to remove resource: " << exc.what(); + VIAM_LOG(error) << "unable to remove resource: " << exc.what(); }; }; @@ -144,8 +144,7 @@ void ResourceManager::replace_one(const Name& name, std::shared_ptr<Resource> re do_remove(name); do_add(name, std::move(resource)); } catch (std::exception& exc) { - BOOST_LOG_TRIVIAL(error) << "failed to replace resource " << name.to_string() << ": " - << exc.what(); + VIAM_LOG(error) << "failed to replace resource " << name.to_string() << ": " << exc.what(); } } From 93119904855a54a4e84458ffae222e5fcaa5353d Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 7 Mar 2025 13:53:06 -0500 Subject: [PATCH 32/86] remove now-unused boost includes and uses of boost log trivial --- src/viam/sdk/common/utils.cpp | 3 --- src/viam/sdk/log/private/log_backend.cpp | 2 -- src/viam/sdk/module/handler_map.cpp | 2 -- src/viam/sdk/module/module.cpp | 3 +-- src/viam/sdk/module/service.cpp | 5 ++--- src/viam/sdk/registry/registry.cpp | 1 - src/viam/sdk/resource/resource.hpp | 2 -- src/viam/sdk/resource/resource_manager.cpp | 2 -- src/viam/sdk/robot/client.cpp | 1 - src/viam/sdk/rpc/server.cpp | 2 -- 10 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/viam/sdk/common/utils.cpp b/src/viam/sdk/common/utils.cpp index 5b1134fec..42039d18f 100644 --- a/src/viam/sdk/common/utils.cpp +++ b/src/viam/sdk/common/utils.cpp @@ -10,9 +10,6 @@ #include <boost/algorithm/string.hpp> #include <boost/blank.hpp> -#include <boost/log/core.hpp> -#include <boost/log/expressions.hpp> -#include <boost/log/trivial.hpp> #include <boost/optional/optional.hpp> #include <viam/api/common/v1/common.pb.h> diff --git a/src/viam/sdk/log/private/log_backend.cpp b/src/viam/sdk/log/private/log_backend.cpp index 1b0ab08e0..9f0a34a7f 100644 --- a/src/viam/sdk/log/private/log_backend.cpp +++ b/src/viam/sdk/log/private/log_backend.cpp @@ -3,8 +3,6 @@ #include <boost/date_time/posix_time/conversion.hpp> #include <boost/smart_ptr/make_shared.hpp> -#include <viam/sdk/log/private/keywords.hpp> - namespace viam { namespace sdk { namespace impl { diff --git a/src/viam/sdk/module/handler_map.cpp b/src/viam/sdk/module/handler_map.cpp index b538ad734..14f5d656d 100644 --- a/src/viam/sdk/module/handler_map.cpp +++ b/src/viam/sdk/module/handler_map.cpp @@ -2,8 +2,6 @@ #include <memory> -#include <boost/log/trivial.hpp> - #include <viam/api/common/v1/common.pb.h> #include <viam/api/module/v1/module.pb.h> #include <viam/api/robot/v1/robot.pb.h> diff --git a/src/viam/sdk/module/module.cpp b/src/viam/sdk/module/module.cpp index 3c09df767..6ccc4b62c 100644 --- a/src/viam/sdk/module/module.cpp +++ b/src/viam/sdk/module/module.cpp @@ -1,6 +1,5 @@ #include <viam/sdk/module/module.hpp> -#include <boost/log/trivial.hpp> #include <grpcpp/channel.h> #include <grpcpp/create_channel.h> #include <grpcpp/security/credentials.h> @@ -10,7 +9,7 @@ namespace viam { namespace sdk { -Module::Module(std::string addr) : addr_(std::move(addr)){}; +Module::Module(std::string addr) : addr_(std::move(addr)) {}; void Module::set_ready() { ready_ = true; diff --git a/src/viam/sdk/module/service.cpp b/src/viam/sdk/module/service.cpp index 5acabe126..fa9d55674 100644 --- a/src/viam/sdk/module/service.cpp +++ b/src/viam/sdk/module/service.cpp @@ -7,7 +7,6 @@ #include <sys/socket.h> #include <sys/stat.h> -#include <boost/log/trivial.hpp> #include <boost/none.hpp> #include <google/protobuf/descriptor.h> #include <grpcpp/channel.h> @@ -108,7 +107,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { try { Stoppable::stop_if_stoppable(res); } catch (const std::exception& err) { - BOOST_LOG_TRIVIAL(error) << "unable to stop resource: " << err.what(); + VIAM_LOG(error) << "unable to stop resource: " << err.what(); } const std::shared_ptr<const ModelRegistration> reg = @@ -169,7 +168,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { try { Stoppable::stop_if_stoppable(res); } catch (const std::exception& err) { - BOOST_LOG_TRIVIAL(error) << "unable to stop resource: " << err.what(); + VIAM_LOG(error) << "unable to stop resource: " << err.what(); } manager->remove(name); diff --git a/src/viam/sdk/registry/registry.cpp b/src/viam/sdk/registry/registry.cpp index e538d2ec2..e0fff782b 100644 --- a/src/viam/sdk/registry/registry.cpp +++ b/src/viam/sdk/registry/registry.cpp @@ -5,7 +5,6 @@ #include <string> #include <unordered_map> -#include <boost/log/trivial.hpp> #include <google/protobuf/descriptor.h> #include <google/protobuf/struct.pb.h> #include <grpcpp/channel.h> diff --git a/src/viam/sdk/resource/resource.hpp b/src/viam/sdk/resource/resource.hpp index 918a988f0..6d05b7cec 100644 --- a/src/viam/sdk/resource/resource.hpp +++ b/src/viam/sdk/resource/resource.hpp @@ -2,8 +2,6 @@ #include <unordered_map> -#include <boost/log/trivial.hpp> - #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/config/resource.hpp> #include <viam/sdk/log/logger.hpp> diff --git a/src/viam/sdk/resource/resource_manager.cpp b/src/viam/sdk/resource/resource_manager.cpp index d67e93972..c68fc0aac 100644 --- a/src/viam/sdk/resource/resource_manager.cpp +++ b/src/viam/sdk/resource/resource_manager.cpp @@ -7,8 +7,6 @@ #include <vector> #include <boost/algorithm/string.hpp> -#include <boost/log/trivial.hpp> -#include <boost/optional/optional.hpp> #include <grpcpp/impl/service_type.h> #include <grpcpp/support/status.h> diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index 3e21adfa4..de1890dbc 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -10,7 +10,6 @@ #include <vector> #include <boost/log/core/core.hpp> -#include <boost/log/trivial.hpp> #include <grpcpp/channel.h> #include <grpcpp/client_context.h> #include <grpcpp/grpcpp.h> diff --git a/src/viam/sdk/rpc/server.cpp b/src/viam/sdk/rpc/server.cpp index 9964abbac..c16394b26 100644 --- a/src/viam/sdk/rpc/server.cpp +++ b/src/viam/sdk/rpc/server.cpp @@ -2,8 +2,6 @@ #include <sstream> -#include <boost/log/trivial.hpp> - #include <grpcpp/impl/service_type.h> #include <grpcpp/security/server_credentials.h> #include <grpcpp/server_builder.h> From a09901f2735a0375ac5c6cb140b097add104123b Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 7 Mar 2025 13:53:28 -0500 Subject: [PATCH 33/86] remove unused log trivial include --- src/viam/examples/modules/complex/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/viam/examples/modules/complex/main.cpp b/src/viam/examples/modules/complex/main.cpp index 253e69d78..cb8fab385 100644 --- a/src/viam/examples/modules/complex/main.cpp +++ b/src/viam/examples/modules/complex/main.cpp @@ -1,7 +1,6 @@ #include <memory> #include <signal.h> -#include <boost/log/trivial.hpp> #include <grpcpp/grpcpp.h> #include <grpcpp/server_context.h> From f9b1cb3e454c3a626527aeb25382eac3628fb94d Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 7 Mar 2025 15:46:47 -0500 Subject: [PATCH 34/86] readability member arrangement/spacing --- src/viam/sdk/config/resource.hpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/viam/sdk/config/resource.hpp b/src/viam/sdk/config/resource.hpp index 73b5c8450..15bb2a5a2 100644 --- a/src/viam/sdk/config/resource.hpp +++ b/src/viam/sdk/config/resource.hpp @@ -61,18 +61,26 @@ class ResourceConfig { const ProtoStruct& attributes() const; private: + void fix_api(); + API api_; + LinkConfig frame_; + Model model_; + std::string name_; std::string namespace__; std::string type_; + std::vector<std::string> depends_on_; + std::vector<ResourceLevelServiceConfig> service_config_; + ProtoStruct attributes_; ProtoValue converted_attributes_; + std::vector<std::string> implicit_depends_on_; - void fix_api(); }; namespace proto_convert_details { From 68add9dc372f99f7b61f715ebe50361712fc0714 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 7 Mar 2025 15:50:44 -0500 Subject: [PATCH 35/86] readability spacing --- src/viam/sdk/config/resource.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/viam/sdk/config/resource.hpp b/src/viam/sdk/config/resource.hpp index 15bb2a5a2..f129a25be 100644 --- a/src/viam/sdk/config/resource.hpp +++ b/src/viam/sdk/config/resource.hpp @@ -50,14 +50,21 @@ class ResourceConfig { ResourceConfig(std::string type); Name resource_name(); + const API& api() const; + const LinkConfig& frame() const; + const Model& model() const; + const std::string& name() const; const std::string& namespace_() const; const std::string& type() const; + const std::vector<std::string>& depends_on() const; + const std::vector<ResourceLevelServiceConfig>& service_config() const; + const ProtoStruct& attributes() const; private: From 05eddd0c09b902a971e20d8e190f77f7321805d2 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 7 Mar 2025 16:33:40 -0500 Subject: [PATCH 36/86] add from string --- src/viam/sdk/log/logger.cpp | 24 ++++++++++++++++++++++++ src/viam/sdk/log/logger.hpp | 2 ++ 2 files changed, 26 insertions(+) diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index d3046e82a..95800f9d5 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -26,6 +26,7 @@ std::string to_string(log_level lvl) { return "info"; case log_level::warn: return "warning"; + // RDK does not support fatal so we send error regardless case log_level::error: // fallthrough case log_level::fatal: return "error"; @@ -34,6 +35,29 @@ std::string to_string(log_level lvl) { } } +log_level level_from_string(std::string str) { + using ll = log_level; + + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + + if (str == "info") { + return ll::info; + } else if (str == "warn" || str == "warning") { + return ll::warn; + } else if (str == "error") { + return ll::error; + } else if (str == "debug") { + return ll::debug; + } else if (str == "trace") { + return ll::trace; + } else if (str == "fatal") { + return ll::fatal; + } + + VIAM_LOG(warn) << "Returning unknown log level " << str << " as info"; + return ll::info; +} + std::ostream& operator<<(std::ostream& os, log_level lvl) { os << to_string(lvl); return os; diff --git a/src/viam/sdk/log/logger.hpp b/src/viam/sdk/log/logger.hpp index b860631f8..82fe12334 100644 --- a/src/viam/sdk/log/logger.hpp +++ b/src/viam/sdk/log/logger.hpp @@ -27,6 +27,8 @@ enum class log_level : std::int8_t { std::string to_string(log_level); +log_level level_from_string(std::string level); + std::ostream& operator<<(std::ostream&, log_level); using LogSource = boost::log::sources::severity_channel_logger_mt<log_level>; From 5debae11719fbd0e31a82fe8b1f95c03fc270ca4 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 7 Mar 2025 16:33:51 -0500 Subject: [PATCH 37/86] add log level --- src/viam/sdk/config/resource.cpp | 14 +++++++++++--- src/viam/sdk/config/resource.hpp | 8 +++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/viam/sdk/config/resource.cpp b/src/viam/sdk/config/resource.cpp index 00d0296f7..3d3251d49 100644 --- a/src/viam/sdk/config/resource.cpp +++ b/src/viam/sdk/config/resource.cpp @@ -26,14 +26,16 @@ ResourceConfig::ResourceConfig(std::string type, ProtoStruct attributes, std::string api, Model model, - LinkConfig frame) + LinkConfig frame, + sdk::log_level lvl) : api_({kRDK, type, ""}), frame_(std::move(frame)), model_(std::move(model)), name_(std::move(name)), namespace__(std::move(namespace_)), type_(std::move(type)), - attributes_(std::move(attributes)) { + attributes_(std::move(attributes)), + log_level_(lvl) { if (api.find(':') != std::string::npos) { api_ = API::from_string(std::move(api)); } @@ -81,6 +83,10 @@ const std::string& ResourceConfig::type() const { return type_; } +log_level ResourceConfig::log_level() const { + return log_level_; +} + const std::vector<std::string>& viam::sdk::ResourceConfig::depends_on() const { return depends_on_; } @@ -137,6 +143,7 @@ void to_proto_impl<ResourceConfig>::operator()(const ResourceConfig& self, *proto->mutable_namespace_() = self.namespace_(); *proto->mutable_type() = self.type(); *proto->mutable_api() = self.api().to_string(); + *proto->mutable_log_configuration()->mutable_level() = to_string(self.log_level()); *proto->mutable_model() = self.model().to_string(); *proto->mutable_attributes() = to_proto(self.attributes()); @@ -154,7 +161,8 @@ ResourceConfig from_proto_impl<app::v1::ComponentConfig>::operator()( from_proto(proto->attributes()), proto->api(), Model::from_str(proto->model()), - proto->has_frame() ? from_proto(proto->frame()) : LinkConfig{}); + proto->has_frame() ? from_proto(proto->frame()) : LinkConfig{}, + level_from_string(proto->log_configuration().level())); } std::vector<ResourceConfig> diff --git a/src/viam/sdk/config/resource.hpp b/src/viam/sdk/config/resource.hpp index f129a25be..ee55d4112 100644 --- a/src/viam/sdk/config/resource.hpp +++ b/src/viam/sdk/config/resource.hpp @@ -5,6 +5,7 @@ #include <viam/sdk/common/proto_convert.hpp> #include <viam/sdk/common/proto_value.hpp> +#include <viam/sdk/log/logger.hpp> #include <viam/sdk/referenceframe/frame.hpp> #include <viam/sdk/resource/resource_api.hpp> @@ -45,7 +46,8 @@ class ResourceConfig { ProtoStruct attributes, std::string api, Model model, - LinkConfig frame); + LinkConfig frame, + sdk::log_level lvl = sdk::log_level::info); ResourceConfig(std::string type); @@ -61,6 +63,8 @@ class ResourceConfig { const std::string& namespace_() const; const std::string& type() const; + log_level log_level() const; + const std::vector<std::string>& depends_on() const; const std::vector<ResourceLevelServiceConfig>& service_config() const; @@ -88,6 +92,8 @@ class ResourceConfig { ProtoValue converted_attributes_; std::vector<std::string> implicit_depends_on_; + + sdk::log_level log_level_; }; namespace proto_convert_details { From 68665679f7f6c9b94027b9ccf2a67078ab79dba2 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 10 Mar 2025 12:08:20 -0400 Subject: [PATCH 38/86] add basic logging tests --- src/viam/sdk/tests/CMakeLists.txt | 1 + src/viam/sdk/tests/test_log.cpp | 93 +++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 src/viam/sdk/tests/test_log.cpp diff --git a/src/viam/sdk/tests/CMakeLists.txt b/src/viam/sdk/tests/CMakeLists.txt index de1fbf0b7..20103f761 100644 --- a/src/viam/sdk/tests/CMakeLists.txt +++ b/src/viam/sdk/tests/CMakeLists.txt @@ -61,6 +61,7 @@ viamcppsdk_add_boost_test(test_discovery.cpp) viamcppsdk_add_boost_test(test_gantry.cpp) viamcppsdk_add_boost_test(test_gripper.cpp) viamcppsdk_add_boost_test(test_generics.cpp) +viamcppsdk_add_boost_test(test_log.cpp) viamcppsdk_add_boost_test(test_mlmodel.cpp) viamcppsdk_add_boost_test(test_motor.cpp) viamcppsdk_add_boost_test(test_motion.cpp) diff --git a/src/viam/sdk/tests/test_log.cpp b/src/viam/sdk/tests/test_log.cpp new file mode 100644 index 000000000..78d13746d --- /dev/null +++ b/src/viam/sdk/tests/test_log.cpp @@ -0,0 +1,93 @@ +#define BOOST_TEST_MODULE test module test_log +#include <viam/sdk/log/logger.hpp> + +#include <iostream> +#include <sstream> + +#include <boost/test/included/unit_test.hpp> + +#include <viam/sdk/resource/resource.hpp> + +namespace viam { +namespace sdktests { + +// Buffer output filter to test console logging. +// In practice this is a pain and makes it hard to inspect Boost.Test output, +// so rather than using it as a test fixture we manually instantiate it in an optional. +// Further log testing is done in the complex module example tests. +// https://stackoverflow.com/a/5405268 +struct cout_redirect { + cout_redirect() : old(std::cout.rdbuf(os.rdbuf())) {} + + void release() { + std::cout.rdbuf(old); + } + + ~cout_redirect() { + release(); + } + + std::ostringstream os; + + private: + std::streambuf* old; +}; + +BOOST_AUTO_TEST_CASE(test_cout_logging) { + cout_redirect redirect; + + VIAM_LOG(info) << "log1"; + + using namespace std::string_literals; + + const std::string rec = redirect.os.str(); + redirect.release(); + + for (const std::string& s : + {"log1"s, to_string(sdk::log_level::info), sdk::global_resource_name()}) { + BOOST_CHECK(rec.find(s) != std::string::npos); + } +} + +BOOST_AUTO_TEST_CASE(test_global_filter) { + cout_redirect redirect; + + VIAM_LOG(info) << "info1"; + VIAM_LOG(error) << "error1"; + VIAM_LOG(trace) << "trace1"; // not logged + + auto& logger = sdk::Logger::get(); + + using ll = sdk::log_level; + + logger.set_global_log_level(ll::trace); + + VIAM_LOG(trace) << "trace2"; + VIAM_LOG(info) << "info2"; + + logger.set_global_log_level(ll::error); + + VIAM_LOG(info) << "info3"; // not logged + VIAM_LOG(error) << "error2"; + + logger.set_global_log_level(ll::info); + + VIAM_LOG(info) << "info4"; + VIAM_LOG(trace) << "trace3"; // once again not logged + + const std::string rec = redirect.os.str(); + redirect.release(); + + for (const char* logged : {"info1", "error1", "trace2", "info2", "error2", "info4"}) { + BOOST_TEST_INFO("Checking for " << logged << " in log rec\n" << rec); + BOOST_CHECK(rec.find(logged) != std::string::npos); + } + + for (const char* not_logged : {"trace1", "info3", "trace3"}) { + BOOST_TEST_INFO("Checking for " << not_logged << " not in log rec\n" << rec); + BOOST_CHECK(rec.find(not_logged) == std::string::npos); + } +} + +} // namespace sdktests +} // namespace viam From f02ce0f75d81baa28d62e88f9771e46132cab562 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:44:21 -0400 Subject: [PATCH 39/86] reorder includes --- src/viam/sdk/tests/test_mlmodel.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/viam/sdk/tests/test_mlmodel.cpp b/src/viam/sdk/tests/test_mlmodel.cpp index 5d2db8010..8bc6a62f0 100644 --- a/src/viam/sdk/tests/test_mlmodel.cpp +++ b/src/viam/sdk/tests/test_mlmodel.cpp @@ -12,20 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +#define BOOST_TEST_MODULE test module test_mlmodel #include <viam/sdk/services/mlmodel.hpp> #include <memory> #include <tuple> #include <unordered_map> +#include <boost/test/included/unit_test.hpp> #include <boost/variant/get.hpp> #include <viam/sdk/tests/mocks/mlmodel_mocks.hpp> #include <viam/sdk/tests/test_utils.hpp> -#define BOOST_TEST_MODULE test module test_mlmodel -#include <boost/test/included/unit_test.hpp> - namespace viam { namespace sdk { From e80bf807136a7b956d1744ac204e27fe6fd39f14 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:45:01 -0400 Subject: [PATCH 40/86] conditionally find unit test framework and link it to tests --- CMakeLists.txt | 6 +++++- src/viam/sdk/tests/CMakeLists.txt | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bebd7564..c025261b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -324,7 +324,11 @@ set(VIAMCPPSDK_XTL_VERSION_MINIMUM 0.7.2) set(VIAMCPPSDK_XTENSOR_VERSION_MINIMUM 0.24.3) # Time to find `BOOST`. -find_package(Boost ${VIAMCPPSDK_BOOST_VERSION_MINIMUM} REQUIRED COMPONENTS headers log program_options) +if (VIAMCPPSDK_BUILD_TESTS) + set(VIAMCPPSDK_BOOST_TEST "unit_test_framework") +endif() + +find_package(Boost ${VIAMCPPSDK_BOOST_VERSION_MINIMUM} REQUIRED COMPONENTS headers log program_options ${VIAMCPPSDK_BOOST_TEST}) # Time to find `protobuf` and `gRPC[++]`. Normally this would just be # something like `find_package(gRPC <version> CONFIG REQUIRED)`, and diff --git a/src/viam/sdk/tests/CMakeLists.txt b/src/viam/sdk/tests/CMakeLists.txt index de1fbf0b7..fa2d1560d 100644 --- a/src/viam/sdk/tests/CMakeLists.txt +++ b/src/viam/sdk/tests/CMakeLists.txt @@ -47,6 +47,7 @@ target_include_directories(viamsdk_test target_link_libraries(viamsdk_test PUBLIC viam-cpp-sdk::viamsdk + PUBLIC Boost::unit_test_framework ) viamcppsdk_link_viam_api(viamsdk_test PUBLIC) From 185121ae13f80aa0c84858e7130349b7a46afd99 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:45:44 -0400 Subject: [PATCH 41/86] registry get cannot create instance by default --- src/viam/sdk/common/instance.cpp | 10 +++++++--- src/viam/sdk/common/instance.hpp | 11 ++++++++++- src/viam/sdk/registry/registry.cpp | 2 +- src/viam/sdk/tests/test_utils.cpp | 2 +- src/viam/sdk/tests/test_utils.hpp | 12 ++++++++++++ 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/viam/sdk/common/instance.cpp b/src/viam/sdk/common/instance.cpp index bc52367f6..86443f458 100644 --- a/src/viam/sdk/common/instance.cpp +++ b/src/viam/sdk/common/instance.cpp @@ -34,10 +34,14 @@ Instance::~Instance() { impl_.reset(); } -Instance& Instance::current() { +Instance& Instance::current(Instance::Creation creation) { if (!current_instance.load()) { - // This variable declaration calls the default ctor, storing a current instance. - static Instance inst; // NOLINT (misc-const-correctness) + if (creation == Creation::if_needed) { + // This variable declaration calls the default ctor, storing a current instance. + static Instance inst; // NOLINT (misc-const-correctness) + } else { + throw Exception("Instance has not yet been created"); + } } Instance* current = current_instance.load(); diff --git a/src/viam/sdk/common/instance.hpp b/src/viam/sdk/common/instance.hpp index 64bb430c2..1dd0901df 100644 --- a/src/viam/sdk/common/instance.hpp +++ b/src/viam/sdk/common/instance.hpp @@ -12,10 +12,19 @@ namespace sdk { /// objects in the same program is an error. class Instance { public: + /// @brief Enumeration for creation behavior of @ref current + enum class Creation { + open_existing, ///< Instance must already exist + if_needed ///< Use existing instance if present, else create one. + }; + Instance(); ~Instance(); - static Instance& current(); + /// @brief Get the current Instance according to the Creation behavior. + /// Calling current(Creation::open_existing) when an instance has not yet been constructed is an + /// error. + static Instance& current(Creation); private: friend class Registry; diff --git a/src/viam/sdk/registry/registry.cpp b/src/viam/sdk/registry/registry.cpp index e538d2ec2..de74d314d 100644 --- a/src/viam/sdk/registry/registry.cpp +++ b/src/viam/sdk/registry/registry.cpp @@ -92,7 +92,7 @@ const Model& ModelRegistration::model() const { }; Registry& Registry::get() { - static Registry& result = Instance::current().impl_->registry; + static Registry& result = Instance::current(Instance::Creation::open_existing).impl_->registry; return result; } diff --git a/src/viam/sdk/tests/test_utils.cpp b/src/viam/sdk/tests/test_utils.cpp index 0ce5c83ca..c83e59580 100644 --- a/src/viam/sdk/tests/test_utils.cpp +++ b/src/viam/sdk/tests/test_utils.cpp @@ -10,8 +10,8 @@ #include <viam/sdk/spatialmath/orientation_types.hpp> namespace viam { -namespace sdktests { +namespace sdktests { using namespace viam::sdk; ProtoStruct fake_map() { diff --git a/src/viam/sdk/tests/test_utils.hpp b/src/viam/sdk/tests/test_utils.hpp index 11519a551..201451188 100644 --- a/src/viam/sdk/tests/test_utils.hpp +++ b/src/viam/sdk/tests/test_utils.hpp @@ -2,6 +2,9 @@ #include <grpcpp/grpcpp.h> +#include <boost/test/unit_test.hpp> + +#include <viam/sdk/common/instance.hpp> #include <viam/sdk/config/resource.hpp> #include <viam/sdk/registry/registry.hpp> #include <viam/sdk/resource/resource.hpp> @@ -10,6 +13,15 @@ namespace viam { namespace sdktests { +struct GlobalFixture { + GlobalFixture() { + BOOST_TEST_MESSAGE("Creating instance"); + (void)sdk::Instance::current(sdk::Instance::Creation::if_needed); + } +}; + +BOOST_TEST_GLOBAL_FIXTURE(GlobalFixture); + using namespace viam::sdk; ProtoStruct fake_map(); From 7a747ec8f99fd9d529db8c37f3713b9d7a6bc7dc Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:48:39 -0400 Subject: [PATCH 42/86] instance models fixture --- src/viam/sdk/tests/test_utils.hpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/viam/sdk/tests/test_utils.hpp b/src/viam/sdk/tests/test_utils.hpp index 201451188..43825b8e2 100644 --- a/src/viam/sdk/tests/test_utils.hpp +++ b/src/viam/sdk/tests/test_utils.hpp @@ -13,16 +13,8 @@ namespace viam { namespace sdktests { -struct GlobalFixture { - GlobalFixture() { - BOOST_TEST_MESSAGE("Creating instance"); - (void)sdk::Instance::current(sdk::Instance::Creation::if_needed); - } -}; - -BOOST_TEST_GLOBAL_FIXTURE(GlobalFixture); - using namespace viam::sdk; +BOOST_TEST_GLOBAL_FIXTURE(Instance); ProtoStruct fake_map(); std::vector<GeometryConfig> fake_geometries(); From 9c4dc97111a2ce43bd8f0f917e0b3566601e0bdd Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:05:15 -0400 Subject: [PATCH 43/86] create if needed instance in fixture --- src/viam/sdk/tests/test_utils.hpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/viam/sdk/tests/test_utils.hpp b/src/viam/sdk/tests/test_utils.hpp index 43825b8e2..bb69e2499 100644 --- a/src/viam/sdk/tests/test_utils.hpp +++ b/src/viam/sdk/tests/test_utils.hpp @@ -13,8 +13,15 @@ namespace viam { namespace sdktests { +struct GlobalFixture { + GlobalFixture() { + (void)sdk::Instance::current(sdk::Instance::Creation::if_needed); + } +}; + +BOOST_TEST_GLOBAL_FIXTURE(GlobalFixture); + using namespace viam::sdk; -BOOST_TEST_GLOBAL_FIXTURE(Instance); ProtoStruct fake_map(); std::vector<GeometryConfig> fake_geometries(); From 7409dc78319586f9141d4070f61b1f30f0b95cab Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 12 Mar 2025 14:08:11 -0400 Subject: [PATCH 44/86] revert namespace ws --- src/viam/sdk/tests/test_utils.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/viam/sdk/tests/test_utils.cpp b/src/viam/sdk/tests/test_utils.cpp index c83e59580..9e76e2568 100644 --- a/src/viam/sdk/tests/test_utils.cpp +++ b/src/viam/sdk/tests/test_utils.cpp @@ -10,7 +10,6 @@ #include <viam/sdk/spatialmath/orientation_types.hpp> namespace viam { - namespace sdktests { using namespace viam::sdk; From c67166becbff5a66000dbd8212c2e5fe0bcdb93c Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 13 Mar 2025 15:08:14 -0400 Subject: [PATCH 45/86] move cout redirect to test_utils --- src/viam/sdk/tests/test_log.cpp | 22 ---------------------- src/viam/sdk/tests/test_utils.hpp | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/viam/sdk/tests/test_log.cpp b/src/viam/sdk/tests/test_log.cpp index d21e3787b..bcf770d7c 100644 --- a/src/viam/sdk/tests/test_log.cpp +++ b/src/viam/sdk/tests/test_log.cpp @@ -12,28 +12,6 @@ namespace viam { namespace sdktests { -// Buffer output filter to test console logging. -// In practice this is a pain and makes it hard to inspect Boost.Test output, -// so rather than using it as a test fixture we manually instantiate it in an optional. -// Further log testing is done in the complex module example tests. -// https://stackoverflow.com/a/5405268 -struct cout_redirect { - cout_redirect() : old(std::cout.rdbuf(os.rdbuf())) {} - - void release() { - std::cout.rdbuf(old); - } - - ~cout_redirect() { - release(); - } - - std::ostringstream os; - - private: - std::streambuf* old; -}; - BOOST_AUTO_TEST_CASE(test_cout_logging) { cout_redirect redirect; diff --git a/src/viam/sdk/tests/test_utils.hpp b/src/viam/sdk/tests/test_utils.hpp index bb69e2499..3184588ab 100644 --- a/src/viam/sdk/tests/test_utils.hpp +++ b/src/viam/sdk/tests/test_utils.hpp @@ -21,6 +21,28 @@ struct GlobalFixture { BOOST_TEST_GLOBAL_FIXTURE(GlobalFixture); +// Buffer output filter to test console logging. +// In practice this is a pain and makes it hard to inspect Boost.Test output, +// so rather than using it as a test fixture we manually instantiate it in an optional. +// Further log testing is done in the complex module example tests. +// https://stackoverflow.com/a/5405268 +struct cout_redirect { + cout_redirect() : old(std::cout.rdbuf(os.rdbuf())) {} + + void release() { + std::cout.rdbuf(old); + } + + ~cout_redirect() { + release(); + } + + std::ostringstream os; + + private: + std::streambuf* old; +}; + using namespace viam::sdk; ProtoStruct fake_map(); From 0745e16320acd9751a00b4ab84ea47cf948b6ace Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 13 Mar 2025 17:15:03 -0400 Subject: [PATCH 46/86] implement set resource log level --- src/viam/sdk/log/logger.cpp | 4 ++++ src/viam/sdk/log/logger.hpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index 370ddf89a..736ad7011 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -100,6 +100,10 @@ void Logger::set_global_log_level(int argc, char** argv) { } } +void Logger::set_resource_log_level(const std::string& resource, log_level lvl) { + resource_levels_[resource] = lvl; +} + void Logger::init_logging() { sdk_logger_.channel(global_resource_name()); boost::log::core::get()->add_global_attribute("TimeStamp", diff --git a/src/viam/sdk/log/logger.hpp b/src/viam/sdk/log/logger.hpp index 82fe12334..a6c955f74 100644 --- a/src/viam/sdk/log/logger.hpp +++ b/src/viam/sdk/log/logger.hpp @@ -55,7 +55,7 @@ class Logger { /// how to start modules with a "log-level" commandline argument. void set_global_log_level(int argc, char** argv); - void set_resource_log_level(std::string resource, log_level); + void set_resource_log_level(const std::string& resource, log_level); LogSource& logger() { return sdk_logger_; From 04edd0d5c6821505584d355b60511005b784fe46 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 13 Mar 2025 17:15:39 -0400 Subject: [PATCH 47/86] implement set resource log level for resource itself --- src/viam/sdk/resource/resource.cpp | 4 ++++ src/viam/sdk/resource/resource.hpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/viam/sdk/resource/resource.cpp b/src/viam/sdk/resource/resource.cpp index 48bbb0f37..3b46fb00d 100644 --- a/src/viam/sdk/resource/resource.cpp +++ b/src/viam/sdk/resource/resource.cpp @@ -29,5 +29,9 @@ Name Resource::get_resource_name() const { return get_resource_name(kResource); } +void Resource::set_log_level(log_level ll) const { + Logger::get().set_resource_log_level(name_, ll); +} + } // namespace sdk } // namespace viam diff --git a/src/viam/sdk/resource/resource.hpp b/src/viam/sdk/resource/resource.hpp index 6d05b7cec..afd3f87d5 100644 --- a/src/viam/sdk/resource/resource.hpp +++ b/src/viam/sdk/resource/resource.hpp @@ -28,6 +28,9 @@ class Resource { /// @brief Return the resource's name. virtual std::string name() const; + /// @brief Set the log level for log messages originating from this Resource. + void set_log_level(log_level) const; + private: std::string name_; From 537ea67b856b1946225ad2712d9a355e5cb1abcc Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 13 Mar 2025 17:15:58 -0400 Subject: [PATCH 48/86] test resource level logging in unit tests --- src/viam/sdk/tests/test_log.cpp | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/viam/sdk/tests/test_log.cpp b/src/viam/sdk/tests/test_log.cpp index bcf770d7c..b06a5c7a1 100644 --- a/src/viam/sdk/tests/test_log.cpp +++ b/src/viam/sdk/tests/test_log.cpp @@ -7,6 +7,7 @@ #include <sstream> #include <viam/sdk/resource/resource.hpp> +#include <viam/sdk/tests/mocks/mock_sensor.hpp> #include <viam/sdk/tests/test_utils.hpp> namespace viam { @@ -68,5 +69,59 @@ BOOST_AUTO_TEST_CASE(test_global_filter) { } } +struct LogSensor : sensor::MockSensor { + using sensor::MockSensor::MockSensor; + + sdk::ProtoStruct get_readings(const sdk::ProtoStruct& extra) override { + VIAM_RESOURCE_LOG(info) << "sensor info"; + VIAM_RESOURCE_LOG(error) << "sensor error"; + return sensor::MockSensor::get_readings(extra); + } +}; + +BOOST_AUTO_TEST_CASE(test_resource_filter) { + cout_redirect redirect; + + auto defaultSensor = std::make_shared<LogSensor>("DefaultSensor"); + auto errorSensor = std::make_shared<LogSensor>("ErrorSensor"); + errorSensor->set_log_level(sdk::log_level::error); + + for (auto sensor : {defaultSensor, errorSensor}) { + client_to_mock_pipeline<Sensor>(sensor, + [&](Sensor& client) { (void)client.get_readings({}); }); + } + + std::vector<std::string> defaultLogs; + std::vector<std::string> errLogs; + + const std::string rec = redirect.os.str(); + BOOST_TEST_INFO("Log records\n" << rec); + + std::stringstream ss(rec); + redirect.release(); + + { + std::string local; + + while (std::getline(ss, local, '\n')) { + if (local.find("DefaultSensor") != std::string::npos) { + defaultLogs.push_back(std::move(local)); + } else if (local.find("ErrorSensor") != std::string::npos) { + errLogs.push_back(std::move(local)); + } + } + } + + BOOST_ASSERT(defaultLogs.size() == 2); + { + BOOST_TEST_MESSAGE("default logs\n" << defaultLogs.front() << "\n" << defaultLogs.back()); + BOOST_CHECK(defaultLogs.front().find("sensor info") != std::string::npos); + BOOST_CHECK(defaultLogs.back().find("sensor error") != std::string::npos); + } + + BOOST_ASSERT(errLogs.size() == 1); + BOOST_CHECK(errLogs.back().find("sensor error") != std::string::npos); +} + } // namespace sdktests } // namespace viam From 56e706c298f903c6cbafe9bd77ee0dab6bf9e51a Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 13 Mar 2025 17:16:26 -0400 Subject: [PATCH 49/86] set resource log level from config in start/reconfigure --- src/viam/sdk/module/service.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/viam/sdk/module/service.cpp b/src/viam/sdk/module/service.cpp index fa9d55674..423acd143 100644 --- a/src/viam/sdk/module/service.cpp +++ b/src/viam/sdk/module/service.cpp @@ -60,6 +60,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { if (reg) { try { res = reg->construct_resource(deps, cfg); + res->set_log_level(cfg.log_level()); } catch (const std::exception& exc) { return grpc::Status(::grpc::INTERNAL, exc.what()); } @@ -98,6 +99,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { } try { Reconfigurable::reconfigure_if_reconfigurable(res, deps, cfg); + res->set_log_level(cfg.log_level()); return grpc::Status(); } catch (const std::exception& exc) { return grpc::Status(::grpc::INTERNAL, exc.what()); From 818825a8fb73bcaf48c01e3cddb75845f7dca7f3 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 14 Mar 2025 11:27:49 -0400 Subject: [PATCH 50/86] conditionally find program options as well --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a1f835df..cf42ab901 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -328,12 +328,16 @@ if (VIAMCPPSDK_BUILD_TESTS) set(VIAMCPPSDK_BOOST_TEST "unit_test_framework") endif() +if (VIAMCPPSDK_BUILD_EXAMPLES) + set(VIAMCPPSDK_BOOST_PROGRAM_OPTIONS "program_options") +endif() + find_package(Boost ${VIAMCPPSDK_BOOST_VERSION_MINIMUM} REQUIRED COMPONENTS headers log log_setup - program_options + ${VIAMCPPSDK_BOOST_PROGRAM_OPTIONS} ${VIAMCPPSDK_BOOST_TEST} ) From 6d43bbd18b3cfec917bd894362ef3595ca59eb37 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 14 Mar 2025 12:02:55 -0400 Subject: [PATCH 51/86] remove trailing semicolon --- src/viam/sdk/module/module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/viam/sdk/module/module.cpp b/src/viam/sdk/module/module.cpp index 6ccc4b62c..7af0fa34b 100644 --- a/src/viam/sdk/module/module.cpp +++ b/src/viam/sdk/module/module.cpp @@ -9,7 +9,7 @@ namespace viam { namespace sdk { -Module::Module(std::string addr) : addr_(std::move(addr)) {}; +Module::Module(std::string addr) : addr_(std::move(addr)) {} void Module::set_ready() { ready_ = true; From de5e33aee351ca13d361e28fd3e8ac86b03b944e Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 14 Mar 2025 12:18:11 -0400 Subject: [PATCH 52/86] private/friend decls --- src/viam/sdk/robot/client.hpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/viam/sdk/robot/client.hpp b/src/viam/sdk/robot/client.hpp index e60eb0edc..8b00d4250 100644 --- a/src/viam/sdk/robot/client.hpp +++ b/src/viam/sdk/robot/client.hpp @@ -20,6 +20,10 @@ namespace viam { namespace sdk { +namespace impl { +struct LogBackend; +} + /// @defgroup Robot Classes related to a Robot representation. /// @class RobotClient client.hpp "robot/client.hpp" @@ -88,13 +92,6 @@ class RobotClient { RobotClient(std::shared_ptr<ViamChannel> channel); - void log(const std::string& name, - const std::string& level, - const std::string& message, - time_pt time); - - void connect_logging(); - std::vector<Name> resource_names() const; /// @brief Lookup and return a `shared_ptr` to a resource. @@ -156,6 +153,16 @@ class RobotClient { status get_machine_status() const; private: + friend class ModuleService; + friend struct impl::LogBackend; + + void log(const std::string& name, + const std::string& level, + const std::string& message, + time_pt time); + + void connect_logging(); + void refresh_every(); std::vector<std::shared_ptr<std::thread>> threads_; From a2865084478500c21f3960a15ecbec73a05eebc0 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 14 Mar 2025 12:18:19 -0400 Subject: [PATCH 53/86] docs --- src/viam/sdk/log/logger.cpp | 4 ++ src/viam/sdk/log/logger.hpp | 59 +++++++++++++++++++++--- src/viam/sdk/log/private/log_backend.hpp | 1 + 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index 736ad7011..565e67faf 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -90,6 +90,10 @@ Logger& Logger::get() { return result; } +LogSource& Logger::logger() { + return sdk_logger_; +} + void Logger::set_global_log_level(log_level lvl) { global_level_ = lvl; } diff --git a/src/viam/sdk/log/logger.hpp b/src/viam/sdk/log/logger.hpp index a6c955f74..c4bf50936 100644 --- a/src/viam/sdk/log/logger.hpp +++ b/src/viam/sdk/log/logger.hpp @@ -1,3 +1,6 @@ +/// @file log/logger.hpp +/// +/// @brief Defines logging infrastructure #pragma once #include <cstdint> @@ -16,6 +19,10 @@ namespace viam { namespace sdk { +/// @defgroup Log Classes related to logging. + +/// @brief Severity levels for the logger. +/// @ingroup Log enum class log_level : std::int8_t { trace = -2, debug = -1, @@ -31,10 +38,23 @@ log_level level_from_string(std::string level); std::ostream& operator<<(std::ostream&, log_level); +/// @brief Type alias for the log source in the C++ SDK. +/// @ingroup Log +/// +/// In the paradigm of Boost.Log the C++ SDK has precisely one logging source, namely the source of +/// messages generated by the user invoking one of the logging macros. using LogSource = boost::log::sources::severity_channel_logger_mt<log_level>; +/// @brief Returns the "channel name" of general log messages not originating from resources. +/// @ingroup Log std::string global_resource_name(); +/// @class Logger logger.hpp "log/logger.hpp" +/// @brief Manages the logging infrastructure in the SDDK. +/// @ingroup Log +/// +/// Handles initialization and bookkeeping for logging infrastructure in the C++ SDK. This includes +/// console logging, if active, and both global and resource-level log filtering. class Logger { public: struct Filter { @@ -43,29 +63,47 @@ class Logger { bool operator()(const boost::log::attribute_value_set&); }; + /// @brief Returns the unique logger instance. + /// + /// This is the only way to access the logger. static Logger& get(); + /// @brief Set the global logger severity. void set_global_log_level(log_level); - /// @brief Set the SDK logger severity from a command line argument vector. + /// @brief Set the global logger severity from a command line argument vector. /// - /// Sets the boost trivial logger's severity to debug if "--log-level=debug" is the + /// Sets severity to debug if "--log-level=debug" is /// the third argument. Sets severity to info otherwise. Useful for module /// implementations. See LogLevel documentation in the RDK for more information on /// how to start modules with a "log-level" commandline argument. void set_global_log_level(int argc, char** argv); + /// @brief Set the logger severity for a resource. + /// + /// Logger can maintain separate severity levels for individual resources. For example, you may + /// want to only report "error" messages for global logs and logs for one component of a modular + /// resource, but enable verbose logging for a new component that is still being debugged. + /// @see @ref Resource, which has a set_log_level method which automatically provides its own + /// resource name. void set_resource_log_level(const std::string& resource, log_level); - LogSource& logger() { - return sdk_logger_; - } + /// @brief Return the SDK global log source. + /// + /// Users should prefer to log messages using the logging macros below. + LogSource& logger(); private: friend class RobotClient; friend class Instance; Logger() = default; + Logger(const Logger&) = delete; + Logger(Logger&&) = delete; + + Logger& operator=(const Logger&) = delete; + Logger& operator=(Logger&&) = delete; + void init_logging(); void disable_console_logging(); @@ -86,14 +124,23 @@ BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_time, "TimeStamp", boost::log::attributes::local_clock::value_type); -// Logging macro for general SDK logs #define VIAM_LOG_IMPL(lg, level) \ BOOST_LOG_SEV((lg), ::viam::sdk::log_level::level) \ << ::boost::log::add_value(::viam::sdk::attr_file_type{}, __FILE__) \ << ::boost::log::add_value(::viam::sdk::attr_line_type{}, __LINE__) +/// @brief Log macro for general SDK logs. +/// @ingroup Log +/// +/// Use this macro to generate log messages pertaining to the SDK at large. #define VIAM_LOG(level) VIAM_LOG_IMPL(::viam::sdk::Logger::get().logger(), level) +/// @brief Log macro for resource-level logs. +/// @ingroup Log +/// +/// This macro can only be called from the definition of a member function of a class inheriting +/// @ref Resource. It will log messages to the log source of that specific resource, allowing +/// resource-level log filtering. #define VIAM_RESOURCE_LOG(level) VIAM_LOG_IMPL(this->logger_, level) } // namespace sdk diff --git a/src/viam/sdk/log/private/log_backend.hpp b/src/viam/sdk/log/private/log_backend.hpp index 8bb2dc4cb..216621e65 100644 --- a/src/viam/sdk/log/private/log_backend.hpp +++ b/src/viam/sdk/log/private/log_backend.hpp @@ -14,6 +14,7 @@ struct LogBackend; using SinkType = boost::log::sinks::synchronous_sink<LogBackend>; +// Log backend which implements sending messages to RDK. struct LogBackend : boost::log::sinks::basic_sink_backend<boost::log::sinks::synchronized_feeding> { LogBackend(RobotClient* p) : parent(p) {} From e45bafc8b3be02507099fd3005e8309561c638b1 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 10:17:35 -0400 Subject: [PATCH 54/86] update method name to avoid conflict --- src/viam/sdk/config/resource.cpp | 4 ++-- src/viam/sdk/config/resource.hpp | 2 +- src/viam/sdk/module/service.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/viam/sdk/config/resource.cpp b/src/viam/sdk/config/resource.cpp index 3d3251d49..23b206efb 100644 --- a/src/viam/sdk/config/resource.cpp +++ b/src/viam/sdk/config/resource.cpp @@ -83,7 +83,7 @@ const std::string& ResourceConfig::type() const { return type_; } -log_level ResourceConfig::log_level() const { +log_level ResourceConfig::get_log_level() const { return log_level_; } @@ -143,7 +143,7 @@ void to_proto_impl<ResourceConfig>::operator()(const ResourceConfig& self, *proto->mutable_namespace_() = self.namespace_(); *proto->mutable_type() = self.type(); *proto->mutable_api() = self.api().to_string(); - *proto->mutable_log_configuration()->mutable_level() = to_string(self.log_level()); + *proto->mutable_log_configuration()->mutable_level() = to_string(self.get_log_level()); *proto->mutable_model() = self.model().to_string(); *proto->mutable_attributes() = to_proto(self.attributes()); diff --git a/src/viam/sdk/config/resource.hpp b/src/viam/sdk/config/resource.hpp index ee55d4112..622c12780 100644 --- a/src/viam/sdk/config/resource.hpp +++ b/src/viam/sdk/config/resource.hpp @@ -63,7 +63,7 @@ class ResourceConfig { const std::string& namespace_() const; const std::string& type() const; - log_level log_level() const; + log_level get_log_level() const; const std::vector<std::string>& depends_on() const; diff --git a/src/viam/sdk/module/service.cpp b/src/viam/sdk/module/service.cpp index 423acd143..3c3b31e04 100644 --- a/src/viam/sdk/module/service.cpp +++ b/src/viam/sdk/module/service.cpp @@ -60,7 +60,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { if (reg) { try { res = reg->construct_resource(deps, cfg); - res->set_log_level(cfg.log_level()); + res->set_log_level(cfg.get_log_level()); } catch (const std::exception& exc) { return grpc::Status(::grpc::INTERNAL, exc.what()); } @@ -99,7 +99,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { } try { Reconfigurable::reconfigure_if_reconfigurable(res, deps, cfg); - res->set_log_level(cfg.log_level()); + res->set_log_level(cfg.get_log_level()); return grpc::Status(); } catch (const std::exception& exc) { return grpc::Status(::grpc::INTERNAL, exc.what()); From 14a60496540aafa711054141e5d8aec9fa232adb Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 11:38:36 -0400 Subject: [PATCH 55/86] const qualify method and member ptr --- src/viam/sdk/log/logger.cpp | 2 +- src/viam/sdk/log/logger.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index 565e67faf..bdd7a51a2 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -67,7 +67,7 @@ std::string global_resource_name() { return "Viam C++ SDK"; } -bool Logger::Filter::operator()(const boost::log::attribute_value_set& attrs) { +bool Logger::Filter::operator()(const boost::log::attribute_value_set& attrs) const { auto sev = attrs[attr_sev_type{}]; if (!sev) { return false; diff --git a/src/viam/sdk/log/logger.hpp b/src/viam/sdk/log/logger.hpp index c4bf50936..fff95a277 100644 --- a/src/viam/sdk/log/logger.hpp +++ b/src/viam/sdk/log/logger.hpp @@ -58,9 +58,9 @@ std::string global_resource_name(); class Logger { public: struct Filter { - Logger* parent; + const Logger* parent; - bool operator()(const boost::log::attribute_value_set&); + bool operator()(const boost::log::attribute_value_set&) const; }; /// @brief Returns the unique logger instance. From 216df1d4556cd7ef8fcafc7133298e79b495a3fc Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 12:40:34 -0400 Subject: [PATCH 56/86] silence tidy error --- src/viam/sdk/log/logger.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index bdd7a51a2..111f09808 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -35,26 +35,26 @@ std::string to_string(log_level lvl) { } } -log_level level_from_string(std::string str) { +log_level level_from_string(std::string level) { using ll = log_level; - std::transform(str.begin(), str.end(), str.begin(), ::tolower); + std::transform(level.begin(), level.end(), level.begin(), ::tolower); - if (str == "info") { + if (level == "info") { return ll::info; - } else if (str == "warn" || str == "warning") { + } else if (level == "warn" || level == "warning") { return ll::warn; - } else if (str == "error") { + } else if (level == "error") { return ll::error; - } else if (str == "debug") { + } else if (level == "debug") { return ll::debug; - } else if (str == "trace") { + } else if (level == "trace") { return ll::trace; - } else if (str == "fatal") { + } else if (level == "fatal") { return ll::fatal; } - VIAM_LOG(warn) << "Returning unknown log level " << str << " as info"; + VIAM_LOG(warn) << "Returning unknown log level " << level << " as info"; return ll::info; } From f4b0f119d74e3ef0daaccbad884b5756bb4b34dd Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 14:29:41 -0400 Subject: [PATCH 57/86] fix file logging --- src/viam/sdk/log/logger.cpp | 17 +++++++++++++++++ src/viam/sdk/log/logger.hpp | 18 ++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index 111f09808..1e5dd7d40 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -137,5 +137,22 @@ void Logger::disable_console_logging() { boost::log::core::get()->remove_sink(console_sink_); } +namespace log_detail { + +boost::string_view trim_filename(const char* file) { + boost::string_view result(file); + const std::size_t second_last = result // + .substr(0, result.find_last_of('/')) + .find_last_of('/'); + + if (second_last != boost::string_view::npos) { + return result.substr(second_last + 1, result.size() - second_last); + } + + return result; +} + +} // namespace log_detail + } // namespace sdk } // namespace viam diff --git a/src/viam/sdk/log/logger.hpp b/src/viam/sdk/log/logger.hpp index fff95a277..93817c142 100644 --- a/src/viam/sdk/log/logger.hpp +++ b/src/viam/sdk/log/logger.hpp @@ -15,6 +15,7 @@ #include <boost/log/sinks/text_ostream_backend.hpp> #include <boost/log/sources/severity_channel_logger.hpp> #include <boost/log/utility/manipulators/add_value.hpp> +#include <boost/utility/string_view.hpp> namespace viam { namespace sdk { @@ -116,17 +117,26 @@ class Logger { std::map<std::string, log_level> resource_levels_; }; +namespace log_detail { + +// Some of the filenames in the SDK are not unique, eg config/resource.hpp, resource/resource.hpp. +// This function trims a full filename /path/to/some/file.xpp to some/file.xpp +boost::string_view trim_filename(const char* file); + +} // namespace log_detail + BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_channel, "Channel", std::string); BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_sev, "Severity", viam::sdk::log_level); -BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_file, "file", const char*); +BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_file, "file", boost::string_view); BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_line, "line", unsigned int); BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_time, "TimeStamp", boost::log::attributes::local_clock::value_type); -#define VIAM_LOG_IMPL(lg, level) \ - BOOST_LOG_SEV((lg), ::viam::sdk::log_level::level) \ - << ::boost::log::add_value(::viam::sdk::attr_file_type{}, __FILE__) \ +#define VIAM_LOG_IMPL(lg, level) \ + BOOST_LOG_SEV((lg), ::viam::sdk::log_level::level) \ + << ::boost::log::add_value(::viam::sdk::attr_file_type{}, \ + ::viam::sdk::log_detail::trim_filename(__FILE__)) \ << ::boost::log::add_value(::viam::sdk::attr_line_type{}, __LINE__) /// @brief Log macro for general SDK logs. From e3e269730a5d7fe451b9255fe8a1add01c204fce Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 14:40:09 -0400 Subject: [PATCH 58/86] handle empty string and clarify level formatting --- src/viam/sdk/config/resource.cpp | 3 ++- src/viam/sdk/log/logger.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/viam/sdk/config/resource.cpp b/src/viam/sdk/config/resource.cpp index 23b206efb..2f0b131ce 100644 --- a/src/viam/sdk/config/resource.cpp +++ b/src/viam/sdk/config/resource.cpp @@ -155,6 +155,7 @@ void to_proto_impl<ResourceConfig>::operator()(const ResourceConfig& self, ResourceConfig from_proto_impl<app::v1::ComponentConfig>::operator()( const app::v1::ComponentConfig* proto) const { + const std::string& level_str = proto->log_configuration().level(); return ResourceConfig(proto->type(), proto->name(), proto->namespace_(), @@ -162,7 +163,7 @@ ResourceConfig from_proto_impl<app::v1::ComponentConfig>::operator()( proto->api(), Model::from_str(proto->model()), proto->has_frame() ? from_proto(proto->frame()) : LinkConfig{}, - level_from_string(proto->log_configuration().level())); + level_str.empty() ? log_level::info : level_from_string(level_str)); } std::vector<ResourceConfig> diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index 1e5dd7d40..b247dc6c2 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -54,7 +54,7 @@ log_level level_from_string(std::string level) { return ll::fatal; } - VIAM_LOG(warn) << "Returning unknown log level " << level << " as info"; + VIAM_LOG(warn) << "Returning unknown log level `" << level << "` as info"; return ll::info; } From bdebbab0cfa60a20d504183eed5966e4e884aa67 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 14:47:14 -0400 Subject: [PATCH 59/86] log the logging --- src/viam/sdk/log/logger.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index b247dc6c2..90f8c994c 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -131,9 +131,11 @@ void Logger::init_logging() { console_sink_->set_formatter(fmt); boost::log::core::get()->add_sink(console_sink_); + VIAM_LOG(info) << "Initialized console logging"; } void Logger::disable_console_logging() { + VIAM_LOG(info) << "Disabling console logging"; boost::log::core::get()->remove_sink(console_sink_); } From 8c372ccb2b16725f082d789ec1254fcca81db5b5 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 15:59:06 -0400 Subject: [PATCH 60/86] linter warnings........... --- src/viam/sdk/log/private/log_backend.cpp | 13 +++++++------ src/viam/sdk/log/private/log_backend.hpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/viam/sdk/log/private/log_backend.cpp b/src/viam/sdk/log/private/log_backend.cpp index 9f0a34a7f..6e917adc5 100644 --- a/src/viam/sdk/log/private/log_backend.cpp +++ b/src/viam/sdk/log/private/log_backend.cpp @@ -8,15 +8,16 @@ namespace sdk { namespace impl { time_pt ptime_convert(const boost::posix_time::ptime& from) { - boost::posix_time::time_duration const time_since_epoch = - from - boost::posix_time::from_time_t(0); - time_pt t = std::chrono::system_clock::from_time_t(time_since_epoch.total_seconds()); - long nsec = - time_since_epoch.fractional_seconds() * (1000000000 / time_since_epoch.ticks_per_second()); + namespace posix_time = boost::posix_time; + + posix_time::time_duration const time_since_epoch = from - posix_time::from_time_t(0); + const time_pt t = std::chrono::system_clock::from_time_t(time_since_epoch.total_seconds()); + const long nsec = time_since_epoch.fractional_seconds() * + (1000000000 / posix_time::time_duration::ticks_per_second()); return t + std::chrono::nanoseconds(nsec); } -void LogBackend::consume(const boost::log::record_view& rec) { +void LogBackend::consume(const boost::log::record_view& rec) const { parent->log(*rec[attr_channel_type{}], to_string(*rec[attr_sev_type{}]), *rec[boost::log::expressions::smessage], diff --git a/src/viam/sdk/log/private/log_backend.hpp b/src/viam/sdk/log/private/log_backend.hpp index 216621e65..a3d2207c0 100644 --- a/src/viam/sdk/log/private/log_backend.hpp +++ b/src/viam/sdk/log/private/log_backend.hpp @@ -18,7 +18,7 @@ using SinkType = boost::log::sinks::synchronous_sink<LogBackend>; struct LogBackend : boost::log::sinks::basic_sink_backend<boost::log::sinks::synchronized_feeding> { LogBackend(RobotClient* p) : parent(p) {} - void consume(const boost::log::record_view&); + void consume(const boost::log::record_view&) const; static boost::shared_ptr<SinkType> create(RobotClient* p); From 1744939c2a8666ab432223f9a37cd5dfdcfae9af Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:00:44 -0400 Subject: [PATCH 61/86] linter..... --- src/viam/sdk/log/logger.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index 90f8c994c..dcb2f97ad 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -113,7 +113,7 @@ void Logger::init_logging() { boost::log::core::get()->add_global_attribute("TimeStamp", boost::log::attributes::local_clock()); - boost::log::formatter fmt = + const boost::log::formatter fmt = boost::log::expressions::stream << boost::log::expressions::format_date_time<boost::posix_time::ptime>( "TimeStamp", "%Y--%m--%d %H:%M:%S") @@ -142,7 +142,7 @@ void Logger::disable_console_logging() { namespace log_detail { boost::string_view trim_filename(const char* file) { - boost::string_view result(file); + const boost::string_view result(file); const std::size_t second_last = result // .substr(0, result.find_last_of('/')) .find_last_of('/'); From d7842c18aa55ebb66db5a3936fe81336fd796fa4 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 17:11:43 -0400 Subject: [PATCH 62/86] add log_setup --- src/viam/config/viam-cpp-sdkConfig.cmake.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/viam/config/viam-cpp-sdkConfig.cmake.in b/src/viam/config/viam-cpp-sdkConfig.cmake.in index 2ee214306..82dbf36fc 100644 --- a/src/viam/config/viam-cpp-sdkConfig.cmake.in +++ b/src/viam/config/viam-cpp-sdkConfig.cmake.in @@ -2,7 +2,7 @@ include(CMakeFindDependencyMacro) -find_dependency(Boost @Boost_VERSION_MAJOR@.@Boost_VERSION_MINOR@ COMPONENTS headers log) +find_dependency(Boost @Boost_VERSION_MAJOR@.@Boost_VERSION_MINOR@ COMPONENTS headers log log_setup) if (@gRPC_FOUND@) find_dependency(gRPC @gRPC_VERSION_MAJOR@.@gRPC_VERSION_MINOR@ CONFIG) From 9829e4418a4ac3d6fafa052c4d9ef1e3fa2cb1ea Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 17:17:09 -0400 Subject: [PATCH 63/86] remove sdk:: --- src/viam/sdk/config/resource.cpp | 2 +- src/viam/sdk/config/resource.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/viam/sdk/config/resource.cpp b/src/viam/sdk/config/resource.cpp index 2f0b131ce..0e02d5b27 100644 --- a/src/viam/sdk/config/resource.cpp +++ b/src/viam/sdk/config/resource.cpp @@ -27,7 +27,7 @@ ResourceConfig::ResourceConfig(std::string type, std::string api, Model model, LinkConfig frame, - sdk::log_level lvl) + log_level lvl) : api_({kRDK, type, ""}), frame_(std::move(frame)), model_(std::move(model)), diff --git a/src/viam/sdk/config/resource.hpp b/src/viam/sdk/config/resource.hpp index 622c12780..9aa8d46c7 100644 --- a/src/viam/sdk/config/resource.hpp +++ b/src/viam/sdk/config/resource.hpp @@ -47,7 +47,7 @@ class ResourceConfig { std::string api, Model model, LinkConfig frame, - sdk::log_level lvl = sdk::log_level::info); + log_level lvl = sdk::log_level::info); ResourceConfig(std::string type); @@ -93,7 +93,7 @@ class ResourceConfig { std::vector<std::string> implicit_depends_on_; - sdk::log_level log_level_; + log_level log_level_; }; namespace proto_convert_details { From e10df010f862a43431c4c20fe9ea0887907d57f2 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 17:22:44 -0400 Subject: [PATCH 64/86] global resource is const char* --- src/viam/sdk/log/logger.cpp | 2 +- src/viam/sdk/log/logger.hpp | 2 +- src/viam/sdk/tests/test_log.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index dcb2f97ad..8c5ff1363 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -63,7 +63,7 @@ std::ostream& operator<<(std::ostream& os, log_level lvl) { return os; } -std::string global_resource_name() { +const char* global_resource_name() { return "Viam C++ SDK"; } diff --git a/src/viam/sdk/log/logger.hpp b/src/viam/sdk/log/logger.hpp index 93817c142..7071f3197 100644 --- a/src/viam/sdk/log/logger.hpp +++ b/src/viam/sdk/log/logger.hpp @@ -48,7 +48,7 @@ using LogSource = boost::log::sources::severity_channel_logger_mt<log_level>; /// @brief Returns the "channel name" of general log messages not originating from resources. /// @ingroup Log -std::string global_resource_name(); +const char* global_resource_name(); /// @class Logger logger.hpp "log/logger.hpp" /// @brief Manages the logging infrastructure in the SDDK. diff --git a/src/viam/sdk/tests/test_log.cpp b/src/viam/sdk/tests/test_log.cpp index b06a5c7a1..c5c5bc265 100644 --- a/src/viam/sdk/tests/test_log.cpp +++ b/src/viam/sdk/tests/test_log.cpp @@ -24,7 +24,7 @@ BOOST_AUTO_TEST_CASE(test_cout_logging) { redirect.release(); for (const std::string& s : - {"log1"s, to_string(sdk::log_level::info), sdk::global_resource_name()}) { + {"log1"s, to_string(sdk::log_level::info), std::string{sdk::global_resource_name()}}) { BOOST_CHECK(rec.find(s) != std::string::npos); } } From 192b29fea6dfc33ce74f0ec565ca5a4fb4fef8e8 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 17:25:27 -0400 Subject: [PATCH 65/86] log log as debug --- src/viam/sdk/log/logger.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index 8c5ff1363..a29716a4f 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -131,11 +131,11 @@ void Logger::init_logging() { console_sink_->set_formatter(fmt); boost::log::core::get()->add_sink(console_sink_); - VIAM_LOG(info) << "Initialized console logging"; + VIAM_LOG(debug) << "Initialized console logging"; } void Logger::disable_console_logging() { - VIAM_LOG(info) << "Disabling console logging"; + VIAM_LOG(debug) << "Disabling console logging"; boost::log::core::get()->remove_sink(console_sink_); } From 2de9f40a41e3385dc820d4e2a769d9d00a34c01b Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 17:37:53 -0400 Subject: [PATCH 66/86] fix out of date comment --- src/viam/sdk/tests/test_utils.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/viam/sdk/tests/test_utils.hpp b/src/viam/sdk/tests/test_utils.hpp index 3184588ab..a06de3a30 100644 --- a/src/viam/sdk/tests/test_utils.hpp +++ b/src/viam/sdk/tests/test_utils.hpp @@ -23,8 +23,7 @@ BOOST_TEST_GLOBAL_FIXTURE(GlobalFixture); // Buffer output filter to test console logging. // In practice this is a pain and makes it hard to inspect Boost.Test output, -// so rather than using it as a test fixture we manually instantiate it in an optional. -// Further log testing is done in the complex module example tests. +// so rather than using it as a test fixture we manually instantiate it and call release when done. // https://stackoverflow.com/a/5405268 struct cout_redirect { cout_redirect() : old(std::cout.rdbuf(os.rdbuf())) {} From d681f6f98c6974bd163a3249253f5bf36c8c1857 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 17:48:43 -0400 Subject: [PATCH 67/86] rename to log manager and global logger --- src/viam/sdk/common/instance.cpp | 2 +- src/viam/sdk/common/instance.hpp | 2 +- src/viam/sdk/common/private/instance.hpp | 2 +- src/viam/sdk/log/logger.cpp | 18 +++++++-------- src/viam/sdk/log/logger.hpp | 29 ++++++++++++------------ src/viam/sdk/module/service.cpp | 2 +- src/viam/sdk/resource/resource.cpp | 2 +- src/viam/sdk/robot/client.cpp | 4 ++-- src/viam/sdk/tests/test_log.cpp | 2 +- 9 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/viam/sdk/common/instance.cpp b/src/viam/sdk/common/instance.cpp index 349ae0107..06baf29f4 100644 --- a/src/viam/sdk/common/instance.cpp +++ b/src/viam/sdk/common/instance.cpp @@ -27,7 +27,7 @@ Instance::Instance() { impl_ = std::make_unique<Instance::Impl>(); impl_->registry.initialize(); - impl_->logger.init_logging(); + impl_->log_mgr.init_logging(); } Instance::~Instance() { diff --git a/src/viam/sdk/common/instance.hpp b/src/viam/sdk/common/instance.hpp index 47e3369e7..de10ae896 100644 --- a/src/viam/sdk/common/instance.hpp +++ b/src/viam/sdk/common/instance.hpp @@ -28,7 +28,7 @@ class Instance { private: friend class Registry; - friend class Logger; + friend class LogManager; struct Impl; std::unique_ptr<Impl> impl_; diff --git a/src/viam/sdk/common/private/instance.hpp b/src/viam/sdk/common/private/instance.hpp index 622cfe354..0ffe4dc13 100644 --- a/src/viam/sdk/common/private/instance.hpp +++ b/src/viam/sdk/common/private/instance.hpp @@ -9,7 +9,7 @@ namespace sdk { struct Instance::Impl { Registry registry; - Logger logger; + LogManager log_mgr; }; } // namespace sdk diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logger.cpp index a29716a4f..3ba95a1af 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logger.cpp @@ -67,7 +67,7 @@ const char* global_resource_name() { return "Viam C++ SDK"; } -bool Logger::Filter::operator()(const boost::log::attribute_value_set& attrs) const { +bool LogManager::Filter::operator()(const boost::log::attribute_value_set& attrs) const { auto sev = attrs[attr_sev_type{}]; if (!sev) { return false; @@ -84,31 +84,31 @@ bool Logger::Filter::operator()(const boost::log::attribute_value_set& attrs) co return *sev >= parent->global_level_; } -Logger& Logger::get() { - static Logger& result = Instance::current(Instance::Creation::open_existing).impl_->logger; +LogManager& LogManager::get() { + static LogManager& result = Instance::current(Instance::Creation::open_existing).impl_->log_mgr; return result; } -LogSource& Logger::logger() { +LogSource& LogManager::global_logger() { return sdk_logger_; } -void Logger::set_global_log_level(log_level lvl) { +void LogManager::set_global_log_level(log_level lvl) { global_level_ = lvl; } -void Logger::set_global_log_level(int argc, char** argv) { +void LogManager::set_global_log_level(int argc, char** argv) { if (argc >= 3 && strcmp(argv[2], "--log-level=debug") == 0) { set_global_log_level(log_level::debug); } } -void Logger::set_resource_log_level(const std::string& resource, log_level lvl) { +void LogManager::set_resource_log_level(const std::string& resource, log_level lvl) { resource_levels_[resource] = lvl; } -void Logger::init_logging() { +void LogManager::init_logging() { sdk_logger_.channel(global_resource_name()); boost::log::core::get()->add_global_attribute("TimeStamp", boost::log::attributes::local_clock()); @@ -134,7 +134,7 @@ void Logger::init_logging() { VIAM_LOG(debug) << "Initialized console logging"; } -void Logger::disable_console_logging() { +void LogManager::disable_console_logging() { VIAM_LOG(debug) << "Disabling console logging"; boost::log::core::get()->remove_sink(console_sink_); } diff --git a/src/viam/sdk/log/logger.hpp b/src/viam/sdk/log/logger.hpp index 7071f3197..c2d592566 100644 --- a/src/viam/sdk/log/logger.hpp +++ b/src/viam/sdk/log/logger.hpp @@ -50,16 +50,16 @@ using LogSource = boost::log::sources::severity_channel_logger_mt<log_level>; /// @ingroup Log const char* global_resource_name(); -/// @class Logger logger.hpp "log/logger.hpp" +/// @class LogManager logger.hpp "log/logger.hpp" /// @brief Manages the logging infrastructure in the SDDK. /// @ingroup Log /// /// Handles initialization and bookkeeping for logging infrastructure in the C++ SDK. This includes /// console logging, if active, and both global and resource-level log filtering. -class Logger { +class LogManager { public: struct Filter { - const Logger* parent; + const LogManager* parent; bool operator()(const boost::log::attribute_value_set&) const; }; @@ -67,7 +67,7 @@ class Logger { /// @brief Returns the unique logger instance. /// /// This is the only way to access the logger. - static Logger& get(); + static LogManager& get(); /// @brief Set the global logger severity. void set_global_log_level(log_level); @@ -82,9 +82,10 @@ class Logger { /// @brief Set the logger severity for a resource. /// - /// Logger can maintain separate severity levels for individual resources. For example, you may - /// want to only report "error" messages for global logs and logs for one component of a modular - /// resource, but enable verbose logging for a new component that is still being debugged. + /// LogManager can maintain separate severity levels for individual resources. For example, you + /// may want to only report "error" messages for global logs and logs for one component of a + /// modular resource, but enable verbose logging for a new component that is still being + /// debugged. /// @see @ref Resource, which has a set_log_level method which automatically provides its own /// resource name. void set_resource_log_level(const std::string& resource, log_level); @@ -92,18 +93,18 @@ class Logger { /// @brief Return the SDK global log source. /// /// Users should prefer to log messages using the logging macros below. - LogSource& logger(); + LogSource& global_logger(); private: friend class RobotClient; friend class Instance; - Logger() = default; + LogManager() = default; - Logger(const Logger&) = delete; - Logger(Logger&&) = delete; + LogManager(const LogManager&) = delete; + LogManager(LogManager&&) = delete; - Logger& operator=(const Logger&) = delete; - Logger& operator=(Logger&&) = delete; + LogManager& operator=(const LogManager&) = delete; + LogManager& operator=(LogManager&&) = delete; void init_logging(); void disable_console_logging(); @@ -143,7 +144,7 @@ BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_time, /// @ingroup Log /// /// Use this macro to generate log messages pertaining to the SDK at large. -#define VIAM_LOG(level) VIAM_LOG_IMPL(::viam::sdk::Logger::get().logger(), level) +#define VIAM_LOG(level) VIAM_LOG_IMPL(::viam::sdk::LogManager::get().global_logger(), level) /// @brief Log macro for resource-level logs. /// @ingroup Log diff --git a/src/viam/sdk/module/service.cpp b/src/viam/sdk/module/service.cpp index 3c3b31e04..a79cb99b1 100644 --- a/src/viam/sdk/module/service.cpp +++ b/src/viam/sdk/module/service.cpp @@ -237,7 +237,7 @@ ModuleService::ModuleService(int argc, } return argv[1]; }()) { - Logger::get().set_global_log_level(argc, argv); + LogManager::get().set_global_log_level(argc, argv); for (auto&& mr : registrations) { Registry::get().register_model(mr); diff --git a/src/viam/sdk/resource/resource.cpp b/src/viam/sdk/resource/resource.cpp index 3b46fb00d..3408f0104 100644 --- a/src/viam/sdk/resource/resource.cpp +++ b/src/viam/sdk/resource/resource.cpp @@ -30,7 +30,7 @@ Name Resource::get_resource_name() const { } void Resource::set_log_level(log_level ll) const { - Logger::get().set_resource_log_level(name_, ll); + LogManager::get().set_resource_log_level(name_, ll); } } // namespace sdk diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index 549583ebf..162e3ee1b 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -101,9 +101,9 @@ void RobotClient::connect_logging() { auto& sink = impl_->log_sink; if (!sink) { sink = sdk::impl::LogBackend::create(this); - sink->set_filter(Logger::Filter{&Logger::get()}); + sink->set_filter(LogManager::Filter{&LogManager::get()}); - Logger::get().disable_console_logging(); + LogManager::get().disable_console_logging(); boost::log::core::get()->add_sink(sink); } } diff --git a/src/viam/sdk/tests/test_log.cpp b/src/viam/sdk/tests/test_log.cpp index c5c5bc265..4533ed987 100644 --- a/src/viam/sdk/tests/test_log.cpp +++ b/src/viam/sdk/tests/test_log.cpp @@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE(test_global_filter) { VIAM_LOG(error) << "error1"; VIAM_LOG(trace) << "trace1"; // not logged - auto& logger = sdk::Logger::get(); + auto& logger = sdk::LogManager::get(); using ll = sdk::log_level; From 3b8d7dcac0db2b1a3d99d399d9b6aae217c85727 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 17 Mar 2025 17:52:33 -0400 Subject: [PATCH 68/86] rename files to logging --- src/viam/sdk/CMakeLists.txt | 4 ++-- src/viam/sdk/common/client_helper.cpp | 2 +- src/viam/sdk/common/private/instance.hpp | 2 +- src/viam/sdk/config/resource.hpp | 2 +- src/viam/sdk/log/{logger.cpp => logging.cpp} | 2 +- src/viam/sdk/log/{logger.hpp => logging.hpp} | 4 ++-- src/viam/sdk/resource/resource.hpp | 2 +- src/viam/sdk/tests/test_log.cpp | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) rename src/viam/sdk/log/{logger.cpp => logging.cpp} (99%) rename src/viam/sdk/log/{logger.hpp => logging.hpp} (98%) diff --git a/src/viam/sdk/CMakeLists.txt b/src/viam/sdk/CMakeLists.txt index efbd6d2fd..b758e97ed 100644 --- a/src/viam/sdk/CMakeLists.txt +++ b/src/viam/sdk/CMakeLists.txt @@ -103,7 +103,7 @@ target_sources(viamsdk components/sensor.cpp components/servo.cpp config/resource.cpp - log/logger.cpp + log/logging.cpp log/private/log_backend.cpp module/handler_map.cpp module/module.cpp @@ -172,7 +172,7 @@ target_sources(viamsdk ../../viam/sdk/components/sensor.hpp ../../viam/sdk/components/servo.hpp ../../viam/sdk/config/resource.hpp - ../../viam/sdk/log/logger.hpp + ../../viam/sdk/log/logging.hpp ../../viam/sdk/module/handler_map.hpp ../../viam/sdk/module/module.hpp ../../viam/sdk/module/service.hpp diff --git a/src/viam/sdk/common/client_helper.cpp b/src/viam/sdk/common/client_helper.cpp index 24eeb7db8..dccd6380b 100644 --- a/src/viam/sdk/common/client_helper.cpp +++ b/src/viam/sdk/common/client_helper.cpp @@ -6,7 +6,7 @@ #include <grpcpp/support/status.h> #include <viam/sdk/common/private/version_metadata.hpp> -#include <viam/sdk/log/logger.hpp> +#include <viam/sdk/log/logging.hpp> namespace viam { namespace sdk { diff --git a/src/viam/sdk/common/private/instance.hpp b/src/viam/sdk/common/private/instance.hpp index 0ffe4dc13..cb09480d9 100644 --- a/src/viam/sdk/common/private/instance.hpp +++ b/src/viam/sdk/common/private/instance.hpp @@ -1,7 +1,7 @@ #pragma once #include <viam/sdk/common/instance.hpp> -#include <viam/sdk/log/logger.hpp> +#include <viam/sdk/log/logging.hpp> #include <viam/sdk/registry/registry.hpp> namespace viam { diff --git a/src/viam/sdk/config/resource.hpp b/src/viam/sdk/config/resource.hpp index 9aa8d46c7..d2531b5ff 100644 --- a/src/viam/sdk/config/resource.hpp +++ b/src/viam/sdk/config/resource.hpp @@ -5,7 +5,7 @@ #include <viam/sdk/common/proto_convert.hpp> #include <viam/sdk/common/proto_value.hpp> -#include <viam/sdk/log/logger.hpp> +#include <viam/sdk/log/logging.hpp> #include <viam/sdk/referenceframe/frame.hpp> #include <viam/sdk/resource/resource_api.hpp> diff --git a/src/viam/sdk/log/logger.cpp b/src/viam/sdk/log/logging.cpp similarity index 99% rename from src/viam/sdk/log/logger.cpp rename to src/viam/sdk/log/logging.cpp index 3ba95a1af..9193a5739 100644 --- a/src/viam/sdk/log/logger.cpp +++ b/src/viam/sdk/log/logging.cpp @@ -1,4 +1,4 @@ -#include <viam/sdk/log/logger.hpp> +#include <viam/sdk/log/logging.hpp> #include <iostream> diff --git a/src/viam/sdk/log/logger.hpp b/src/viam/sdk/log/logging.hpp similarity index 98% rename from src/viam/sdk/log/logger.hpp rename to src/viam/sdk/log/logging.hpp index c2d592566..00fc03c15 100644 --- a/src/viam/sdk/log/logger.hpp +++ b/src/viam/sdk/log/logging.hpp @@ -1,4 +1,4 @@ -/// @file log/logger.hpp +/// @file log/logging.hpp /// /// @brief Defines logging infrastructure #pragma once @@ -50,7 +50,7 @@ using LogSource = boost::log::sources::severity_channel_logger_mt<log_level>; /// @ingroup Log const char* global_resource_name(); -/// @class LogManager logger.hpp "log/logger.hpp" +/// @class LogManager logging.hpp "log/logging.hpp" /// @brief Manages the logging infrastructure in the SDDK. /// @ingroup Log /// diff --git a/src/viam/sdk/resource/resource.hpp b/src/viam/sdk/resource/resource.hpp index afd3f87d5..b6f31359b 100644 --- a/src/viam/sdk/resource/resource.hpp +++ b/src/viam/sdk/resource/resource.hpp @@ -4,7 +4,7 @@ #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/config/resource.hpp> -#include <viam/sdk/log/logger.hpp> +#include <viam/sdk/log/logging.hpp> #include <viam/sdk/resource/resource_api.hpp> namespace viam { diff --git a/src/viam/sdk/tests/test_log.cpp b/src/viam/sdk/tests/test_log.cpp index 4533ed987..a25ea536e 100644 --- a/src/viam/sdk/tests/test_log.cpp +++ b/src/viam/sdk/tests/test_log.cpp @@ -1,7 +1,7 @@ #define BOOST_TEST_MODULE test module test_log #include <boost/test/included/unit_test.hpp> -#include <viam/sdk/log/logger.hpp> +#include <viam/sdk/log/logging.hpp> #include <iostream> #include <sstream> From 82eb40362c652a3ca57e5b3751507b54a768ad79 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 18 Mar 2025 11:58:38 -0400 Subject: [PATCH 69/86] use has_log_configuration --- src/viam/sdk/config/resource.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/viam/sdk/config/resource.cpp b/src/viam/sdk/config/resource.cpp index 0e02d5b27..8f19dadef 100644 --- a/src/viam/sdk/config/resource.cpp +++ b/src/viam/sdk/config/resource.cpp @@ -155,7 +155,6 @@ void to_proto_impl<ResourceConfig>::operator()(const ResourceConfig& self, ResourceConfig from_proto_impl<app::v1::ComponentConfig>::operator()( const app::v1::ComponentConfig* proto) const { - const std::string& level_str = proto->log_configuration().level(); return ResourceConfig(proto->type(), proto->name(), proto->namespace_(), @@ -163,7 +162,9 @@ ResourceConfig from_proto_impl<app::v1::ComponentConfig>::operator()( proto->api(), Model::from_str(proto->model()), proto->has_frame() ? from_proto(proto->frame()) : LinkConfig{}, - level_str.empty() ? log_level::info : level_from_string(level_str)); + proto->has_log_configuration() + ? level_from_string(proto->log_configuration().level()) + : log_level::info); } std::vector<ResourceConfig> From ad079c8f056127ab028e193de0aaf1a2cf82d97c Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 18 Mar 2025 12:06:32 -0400 Subject: [PATCH 70/86] unit test trim filename --- src/viam/sdk/tests/test_log.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/viam/sdk/tests/test_log.cpp b/src/viam/sdk/tests/test_log.cpp index a25ea536e..ad1c69f3c 100644 --- a/src/viam/sdk/tests/test_log.cpp +++ b/src/viam/sdk/tests/test_log.cpp @@ -123,5 +123,15 @@ BOOST_AUTO_TEST_CASE(test_resource_filter) { BOOST_CHECK(errLogs.back().find("sensor error") != std::string::npos); } +BOOST_AUTO_TEST_CASE(filename_trim) { + using namespace log_detail; + + BOOST_CHECK(trim_filename("") == ""); + BOOST_CHECK(trim_filename("no_delim") == "no_delim"); + BOOST_CHECK(trim_filename("one/slash.cpp") == "one/slash.cpp"); + BOOST_CHECK(trim_filename("a/full/path.cpp") == "full/path.cpp"); + BOOST_CHECK(trim_filename("a/b/c/d.cpp") == "c/d.cpp"); +} + } // namespace sdktests } // namespace viam From 6b83aedab2ef065e21075b0e6d4cd7bfe099022a Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Tue, 18 Mar 2025 17:16:47 -0400 Subject: [PATCH 71/86] handle fallback console logging for grpc log failures --- src/viam/sdk/log/logging.cpp | 14 +++++++++++++- src/viam/sdk/log/private/log_backend.hpp | 5 +++++ src/viam/sdk/robot/client.cpp | 18 ++++++++++++++++-- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/viam/sdk/log/logging.cpp b/src/viam/sdk/log/logging.cpp index 9193a5739..839fed7d0 100644 --- a/src/viam/sdk/log/logging.cpp +++ b/src/viam/sdk/log/logging.cpp @@ -12,6 +12,7 @@ #include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/private/instance.hpp> +#include <viam/sdk/log/private/log_backend.hpp> namespace viam { namespace sdk { @@ -136,7 +137,18 @@ void LogManager::init_logging() { void LogManager::disable_console_logging() { VIAM_LOG(debug) << "Disabling console logging"; - boost::log::core::get()->remove_sink(console_sink_); + + // Set a filter which ignores all console logs unless they contain a console force flag which is + // set to true. + console_sink_->set_filter( + [filter = Filter{this}](const boost::log::attribute_value_set& attrs) { + auto force = attrs[impl::attr_console_force_type{}]; + if (force && *force) { + return filter(attrs); + } + + return false; + }); } namespace log_detail { diff --git a/src/viam/sdk/log/private/log_backend.hpp b/src/viam/sdk/log/private/log_backend.hpp index a3d2207c0..73e26fc3f 100644 --- a/src/viam/sdk/log/private/log_backend.hpp +++ b/src/viam/sdk/log/private/log_backend.hpp @@ -25,6 +25,11 @@ struct LogBackend : boost::log::sinks::basic_sink_backend<boost::log::sinks::syn RobotClient* parent; }; +// TBD if we want to expose this to users, but for now it is an implementation detail. +// Disabling console logging is implemented by changing the filter on the console sink to reject all +// messages unless they have a "force" flag set to true. +BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_console_force, "force", bool); + } // namespace impl } // namespace sdk } // namespace viam diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index 162e3ee1b..147300502 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -101,7 +101,15 @@ void RobotClient::connect_logging() { auto& sink = impl_->log_sink; if (!sink) { sink = sdk::impl::LogBackend::create(this); - sink->set_filter(LogManager::Filter{&LogManager::get()}); + sink->set_filter([filter = LogManager::Filter{&LogManager::get()}]( + const boost::log::attribute_value_set& attrs) { + auto force = attrs[sdk::impl::attr_console_force_type{}]; + if (force && *force) { + return false; + } + + return filter(attrs); + }); LogManager::get().disable_console_logging(); boost::log::core::get()->add_sink(sink); @@ -270,7 +278,13 @@ void RobotClient::log(const std::string& name, robot::v1::LogResponse resp; ClientContext ctx; const auto response = impl_->stub_->Log(ctx, req, &resp); - (void)response; + if (is_error_response(response)) { + // Manually override to force this to get logged to console so we don't set off an infinite + // loop + VIAM_LOG(error) << boost::log::add_value(sdk::impl::attr_console_force_type{}, true) + << "Error sending log message over grpc: " << response.error_message() + << response.error_details(); + } } std::shared_ptr<RobotClient> RobotClient::with_channel(std::shared_ptr<ViamChannel> channel, From 4eb8643121400d4efa567424981d5e87d65a429a Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 19 Mar 2025 13:07:00 -0400 Subject: [PATCH 72/86] add logging to simple module example --- src/viam/examples/modules/simple/main.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/viam/examples/modules/simple/main.cpp b/src/viam/examples/modules/simple/main.cpp index e85c2fe3a..10f7f667c 100644 --- a/src/viam/examples/modules/simple/main.cpp +++ b/src/viam/examples/modules/simple/main.cpp @@ -7,6 +7,7 @@ #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/components/sensor.hpp> #include <viam/sdk/config/resource.hpp> +#include <viam/sdk/log/logging.hpp> #include <viam/sdk/module/service.hpp> #include <viam/sdk/registry/registry.hpp> #include <viam/sdk/resource/reconfigurable.hpp> @@ -65,7 +66,9 @@ void MySensor::reconfigure(const Dependencies&, const ResourceConfig& cfg) { ProtoStruct MySensor::do_command(const ProtoStruct& command) { for (const auto& entry : command) { - std::cout << "Command entry " << entry.first; + // The VIAM_RESOURCE_LOG macro will associate log messages to the current resource and can + // be filtered upon + VIAM_RESOURCE_LOG(info) << "Command entry " << entry.first; } return command; @@ -80,6 +83,9 @@ int main(int argc, char** argv) try { // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. Instance inst; + // Write general log statements with the VIAM_LOG macro + VIAM_LOG(info) << "Starting up simple sensor module"; + Model mysensor_model("viam", "sensor", "mysensor"); std::shared_ptr<ModelRegistration> mr = std::make_shared<ModelRegistration>( From 418f882aabd7ec0a6ee55d922a8b03f9d25325b1 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 19 Mar 2025 13:12:29 -0400 Subject: [PATCH 73/86] add logging to complex module example --- src/viam/examples/modules/complex/base/impl.cpp | 5 +++-- src/viam/examples/modules/complex/gizmo/impl.cpp | 1 - src/viam/examples/modules/complex/main.cpp | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/viam/examples/modules/complex/base/impl.cpp b/src/viam/examples/modules/complex/base/impl.cpp index 14ed4bb4d..0672076a7 100644 --- a/src/viam/examples/modules/complex/base/impl.cpp +++ b/src/viam/examples/modules/complex/base/impl.cpp @@ -2,7 +2,6 @@ #include <exception> #include <fstream> -#include <iostream> #include <sstream> #include <grpcpp/support/status.h> @@ -10,6 +9,7 @@ #include <viam/sdk/components/base.hpp> #include <viam/sdk/components/component.hpp> #include <viam/sdk/config/resource.hpp> +#include <viam/sdk/log/logging.hpp> #include <viam/sdk/resource/resource.hpp> using namespace viam::sdk; @@ -106,7 +106,8 @@ void MyBase::set_power(const Vector3& linear, const Vector3& angular, const Prot } ProtoStruct MyBase::do_command(const ProtoStruct& command) { - std::cout << "Received DoCommand request for MyBase " << Resource::name() << std::endl; + // The VIAM_RESOURCE_LOG macro will associate log messages to the current resource + VIAM_RESOURCE_LOG(info) << "Received DoCommand request"; return command; } diff --git a/src/viam/examples/modules/complex/gizmo/impl.cpp b/src/viam/examples/modules/complex/gizmo/impl.cpp index adbf8675a..93a21fb18 100644 --- a/src/viam/examples/modules/complex/gizmo/impl.cpp +++ b/src/viam/examples/modules/complex/gizmo/impl.cpp @@ -1,7 +1,6 @@ #include "impl.hpp" #include <fstream> -#include <iostream> #include <sstream> #include <vector> diff --git a/src/viam/examples/modules/complex/main.cpp b/src/viam/examples/modules/complex/main.cpp index cb8fab385..46042597a 100644 --- a/src/viam/examples/modules/complex/main.cpp +++ b/src/viam/examples/modules/complex/main.cpp @@ -8,6 +8,7 @@ #include <viam/sdk/components/base.hpp> #include <viam/sdk/components/component.hpp> #include <viam/sdk/config/resource.hpp> +#include <viam/sdk/log/logging.hpp> #include <viam/sdk/module/module.hpp> #include <viam/sdk/module/service.hpp> #include <viam/sdk/registry/registry.hpp> @@ -47,6 +48,9 @@ int main(int argc, char** argv) { [](Dependencies deps, ResourceConfig cfg) { return std::make_unique<MyGizmo>(deps, cfg); }, MyGizmo::validate); + // Write general log statements with the VIAM_LOG macro + VIAM_LOG(info) << "Registered mybase and mygizmo"; + Model mysummation_model("viam", "summation", "mysummation"); std::shared_ptr<ModelRegistration> mysummation_mr = std::make_shared<ModelRegistration>( From 40b540025479b6e706223071fbddbd104dea0ce1 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 20 Mar 2025 11:48:34 -0400 Subject: [PATCH 74/86] use VIAM_SDK macro prefix --- src/viam/examples/modules/complex/main.cpp | 4 +-- src/viam/examples/modules/simple/main.cpp | 4 +-- src/viam/sdk/common/client_helper.cpp | 4 +-- src/viam/sdk/log/logging.cpp | 6 ++-- src/viam/sdk/log/logging.hpp | 6 ++-- src/viam/sdk/module/handler_map.cpp | 2 +- src/viam/sdk/module/service.cpp | 12 ++++---- src/viam/sdk/resource/resource_manager.cpp | 9 +++--- src/viam/sdk/robot/client.cpp | 34 +++++++++++----------- src/viam/sdk/tests/test_log.cpp | 20 ++++++------- 10 files changed, 51 insertions(+), 50 deletions(-) diff --git a/src/viam/examples/modules/complex/main.cpp b/src/viam/examples/modules/complex/main.cpp index 46042597a..91dbe3a2c 100644 --- a/src/viam/examples/modules/complex/main.cpp +++ b/src/viam/examples/modules/complex/main.cpp @@ -48,8 +48,8 @@ int main(int argc, char** argv) { [](Dependencies deps, ResourceConfig cfg) { return std::make_unique<MyGizmo>(deps, cfg); }, MyGizmo::validate); - // Write general log statements with the VIAM_LOG macro - VIAM_LOG(info) << "Registered mybase and mygizmo"; + // Write general log statements with the VIAM_SDK_LOG macro + VIAM_SDK_LOG(info) << "Registered mybase and mygizmo"; Model mysummation_model("viam", "summation", "mysummation"); diff --git a/src/viam/examples/modules/simple/main.cpp b/src/viam/examples/modules/simple/main.cpp index 10f7f667c..10f791d76 100644 --- a/src/viam/examples/modules/simple/main.cpp +++ b/src/viam/examples/modules/simple/main.cpp @@ -83,8 +83,8 @@ int main(int argc, char** argv) try { // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. Instance inst; - // Write general log statements with the VIAM_LOG macro - VIAM_LOG(info) << "Starting up simple sensor module"; + // Write general log statements with the VIAM_SDK_LOG macro + VIAM_SDK_LOG(info) << "Starting up simple sensor module"; Model mysensor_model("viam", "sensor", "mysensor"); diff --git a/src/viam/sdk/common/client_helper.cpp b/src/viam/sdk/common/client_helper.cpp index dccd6380b..a6853a748 100644 --- a/src/viam/sdk/common/client_helper.cpp +++ b/src/viam/sdk/common/client_helper.cpp @@ -14,8 +14,8 @@ namespace sdk { namespace client_helper_details { [[noreturn]] void errorHandlerReturnedUnexpectedly(const ::grpc::Status* status) noexcept { - VIAM_LOG(fatal) << "ClientHelper error handler callback returned instead of throwing: " - << status->error_message() << '(' << status->error_details() << ')'; + VIAM_SDK_LOG(fatal) << "ClientHelper error handler callback returned instead of throwing: " + << status->error_message() << '(' << status->error_details() << ')'; std::abort(); } diff --git a/src/viam/sdk/log/logging.cpp b/src/viam/sdk/log/logging.cpp index 839fed7d0..024a622ca 100644 --- a/src/viam/sdk/log/logging.cpp +++ b/src/viam/sdk/log/logging.cpp @@ -55,7 +55,7 @@ log_level level_from_string(std::string level) { return ll::fatal; } - VIAM_LOG(warn) << "Returning unknown log level `" << level << "` as info"; + VIAM_SDK_LOG(warn) << "Returning unknown log level `" << level << "` as info"; return ll::info; } @@ -132,11 +132,11 @@ void LogManager::init_logging() { console_sink_->set_formatter(fmt); boost::log::core::get()->add_sink(console_sink_); - VIAM_LOG(debug) << "Initialized console logging"; + VIAM_SDK_LOG(debug) << "Initialized console logging"; } void LogManager::disable_console_logging() { - VIAM_LOG(debug) << "Disabling console logging"; + VIAM_SDK_LOG(debug) << "Disabling console logging"; // Set a filter which ignores all console logs unless they contain a console force flag which is // set to true. diff --git a/src/viam/sdk/log/logging.hpp b/src/viam/sdk/log/logging.hpp index 00fc03c15..93bdaa044 100644 --- a/src/viam/sdk/log/logging.hpp +++ b/src/viam/sdk/log/logging.hpp @@ -134,7 +134,7 @@ BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_time, "TimeStamp", boost::log::attributes::local_clock::value_type); -#define VIAM_LOG_IMPL(lg, level) \ +#define VIAM_SDK_LOG_IMPL(lg, level) \ BOOST_LOG_SEV((lg), ::viam::sdk::log_level::level) \ << ::boost::log::add_value(::viam::sdk::attr_file_type{}, \ ::viam::sdk::log_detail::trim_filename(__FILE__)) \ @@ -144,7 +144,7 @@ BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_time, /// @ingroup Log /// /// Use this macro to generate log messages pertaining to the SDK at large. -#define VIAM_LOG(level) VIAM_LOG_IMPL(::viam::sdk::LogManager::get().global_logger(), level) +#define VIAM_SDK_LOG(level) VIAM_SDK_LOG_IMPL(::viam::sdk::LogManager::get().global_logger(), level) /// @brief Log macro for resource-level logs. /// @ingroup Log @@ -152,7 +152,7 @@ BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE(attr_time, /// This macro can only be called from the definition of a member function of a class inheriting /// @ref Resource. It will log messages to the log source of that specific resource, allowing /// resource-level log filtering. -#define VIAM_RESOURCE_LOG(level) VIAM_LOG_IMPL(this->logger_, level) +#define VIAM_RESOURCE_LOG(level) VIAM_SDK_LOG_IMPL(this->logger_, level) } // namespace sdk } // namespace viam diff --git a/src/viam/sdk/module/handler_map.cpp b/src/viam/sdk/module/handler_map.cpp index 14f5d656d..44a902e66 100644 --- a/src/viam/sdk/module/handler_map.cpp +++ b/src/viam/sdk/module/handler_map.cpp @@ -64,7 +64,7 @@ HandlerMap_ from_proto_impl<module::v1::HandlerMap>::operator()( try { hm.add_model(Model::from_str(mod), handle); } catch (const std::exception& ex) { - VIAM_LOG(error) << "Error " << ex.what() << " processing model " + mod; + VIAM_SDK_LOG(error) << "Error " << ex.what() << " processing model " + mod; } } } diff --git a/src/viam/sdk/module/service.cpp b/src/viam/sdk/module/service.cpp index a79cb99b1..c22e21fe9 100644 --- a/src/viam/sdk/module/service.cpp +++ b/src/viam/sdk/module/service.cpp @@ -109,7 +109,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { try { Stoppable::stop_if_stoppable(res); } catch (const std::exception& err) { - VIAM_LOG(error) << "unable to stop resource: " << err.what(); + VIAM_SDK_LOG(error) << "unable to stop resource: " << err.what(); } const std::shared_ptr<const ModelRegistration> reg = @@ -170,7 +170,7 @@ struct ModuleService::ServiceImpl : viam::module::v1::ModuleService::Service { try { Stoppable::stop_if_stoppable(res); } catch (const std::exception& err) { - VIAM_LOG(error) << "unable to stop resource: " << err.what(); + VIAM_SDK_LOG(error) << "unable to stop resource: " << err.what(); } manager->remove(name); @@ -247,14 +247,14 @@ ModuleService::ModuleService(int argc, ModuleService::~ModuleService() { // TODO(RSDK-5509): Run registered cleanup functions here. - VIAM_LOG(info) << "Shutting down gracefully."; + VIAM_SDK_LOG(info) << "Shutting down gracefully."; server_->shutdown(); if (parent_) { try { parent_->close(); } catch (const std::exception& exc) { - VIAM_LOG(error) << exc.what(); + VIAM_SDK_LOG(error) << exc.what(); } } } @@ -272,8 +272,8 @@ void ModuleService::serve() { module_->set_ready(); server_->start(); - VIAM_LOG(info) << "Module listening on " << module_->addr(); - VIAM_LOG(info) << "Module handles the following API/model pairs:\n" << module_->handles(); + VIAM_SDK_LOG(info) << "Module listening on " << module_->addr(); + VIAM_SDK_LOG(info) << "Module handles the following API/model pairs:\n" << module_->handles(); signal_manager_.wait(); } diff --git a/src/viam/sdk/resource/resource_manager.cpp b/src/viam/sdk/resource/resource_manager.cpp index c68fc0aac..40dc64ece 100644 --- a/src/viam/sdk/resource/resource_manager.cpp +++ b/src/viam/sdk/resource/resource_manager.cpp @@ -50,7 +50,7 @@ void ResourceManager::replace_all( try { do_add(resource.first, resource.second); } catch (std::exception& exc) { - VIAM_LOG(error) << "Error replacing all resources" << exc.what(); + VIAM_SDK_LOG(error) << "Error replacing all resources" << exc.what(); return; } } @@ -95,7 +95,7 @@ void ResourceManager::add(const Name& name, std::shared_ptr<Resource> resource) try { do_add(name, std::move(resource)); } catch (std::exception& exc) { - VIAM_LOG(error) << "Error adding resource to subtype service: " << exc.what(); + VIAM_SDK_LOG(error) << "Error adding resource to subtype service: " << exc.what(); } }; @@ -132,7 +132,7 @@ void ResourceManager::remove(const Name& name) { try { do_remove(name); } catch (std::exception& exc) { - VIAM_LOG(error) << "unable to remove resource: " << exc.what(); + VIAM_SDK_LOG(error) << "unable to remove resource: " << exc.what(); }; }; @@ -142,7 +142,8 @@ void ResourceManager::replace_one(const Name& name, std::shared_ptr<Resource> re do_remove(name); do_add(name, std::move(resource)); } catch (std::exception& exc) { - VIAM_LOG(error) << "failed to replace resource " << name.to_string() << ": " << exc.what(); + VIAM_SDK_LOG(error) << "failed to replace resource " << name.to_string() << ": " + << exc.what(); } } diff --git a/src/viam/sdk/robot/client.cpp b/src/viam/sdk/robot/client.cpp index 147300502..222870003 100644 --- a/src/viam/sdk/robot/client.cpp +++ b/src/viam/sdk/robot/client.cpp @@ -121,9 +121,9 @@ RobotClient::~RobotClient() { try { this->close(); } catch (const std::exception& e) { - VIAM_LOG(error) << "Received err while closing RobotClient: " << e.what(); + VIAM_SDK_LOG(error) << "Received err while closing RobotClient: " << e.what(); } catch (...) { - VIAM_LOG(error) << "Received unknown err while closing RobotClient"; + VIAM_SDK_LOG(error) << "Received unknown err while closing RobotClient"; } } } @@ -150,7 +150,7 @@ std::vector<RobotClient::operation> RobotClient::get_operations() { grpc::Status const response = impl_->stub_->GetOperations(ctx, req, &resp); if (is_error_response(response)) { - VIAM_LOG(error) << "Error getting operations: " << response.error_message(); + VIAM_SDK_LOG(error) << "Error getting operations: " << response.error_message(); } for (int i = 0; i < resp.operations().size(); ++i) { @@ -168,7 +168,7 @@ void RobotClient::cancel_operation(std::string id) { req.set_id(id); const grpc::Status response = impl_->stub_->CancelOperation(ctx, req, &resp); if (is_error_response(response)) { - VIAM_LOG(error) << "Error canceling operation with id " << id; + VIAM_SDK_LOG(error) << "Error canceling operation with id " << id; } } @@ -181,7 +181,7 @@ void RobotClient::block_for_operation(std::string id) { const grpc::Status response = impl_->stub_->BlockForOperation(ctx, req, &resp); if (is_error_response(response)) { - VIAM_LOG(error) << "Error blocking for operation with id " << id; + VIAM_SDK_LOG(error) << "Error blocking for operation with id " << id; } } @@ -192,7 +192,7 @@ void RobotClient::refresh() { const grpc::Status response = impl_->stub_->ResourceNames(ctx, req, &resp); if (is_error_response(response)) { - VIAM_LOG(error) << "Error getting resource names: " << response.error_message(); + VIAM_SDK_LOG(error) << "Error getting resource names: " << response.error_message(); } std::unordered_map<Name, std::shared_ptr<Resource>> new_resources; @@ -216,8 +216,8 @@ void RobotClient::refresh() { const Name name_({name.namespace_(), name.type(), name.subtype()}, "", name.name()); new_resources.emplace(name_, rpc_client); } catch (const std::exception& exc) { - VIAM_LOG(debug) << "Error registering component " << name.subtype() << ": " - << exc.what(); + VIAM_SDK_LOG(debug) + << "Error registering component " << name.subtype() << ": " << exc.what(); } } } @@ -281,9 +281,9 @@ void RobotClient::log(const std::string& name, if (is_error_response(response)) { // Manually override to force this to get logged to console so we don't set off an infinite // loop - VIAM_LOG(error) << boost::log::add_value(sdk::impl::attr_console_force_type{}, true) - << "Error sending log message over grpc: " << response.error_message() - << response.error_details(); + VIAM_SDK_LOG(error) << boost::log::add_value(sdk::impl::attr_console_force_type{}, true) + << "Error sending log message over grpc: " << response.error_message() + << response.error_details(); } } @@ -339,7 +339,7 @@ std::vector<RobotClient::frame_system_config> RobotClient::get_frame_system_conf const grpc::Status response = impl_->stub_->FrameSystemConfig(ctx, req, &resp); if (is_error_response(response)) { - VIAM_LOG(error) << "Error getting frame system config: " << response.error_message(); + VIAM_SDK_LOG(error) << "Error getting frame system config: " << response.error_message(); } const RepeatedPtrField<FrameSystemConfig> configs = resp.frame_system_configs(); @@ -367,7 +367,7 @@ pose_in_frame RobotClient::transform_pose( const grpc::Status response = impl_->stub_->TransformPose(ctx, req, &resp); if (is_error_response(response)) { - VIAM_LOG(error) << "Error getting PoseInFrame: " << response.error_message(); + VIAM_SDK_LOG(error) << "Error getting PoseInFrame: " << response.error_message(); } return from_proto(resp.pose()); @@ -402,8 +402,8 @@ void RobotClient::stop_all(const std::unordered_map<Name, ProtoStruct>& extra) { } const grpc::Status response = impl_->stub_->StopAll(ctx, req, &resp); if (is_error_response(response)) { - VIAM_LOG(error) << "Error stopping all: " << response.error_message() - << response.error_details(); + VIAM_SDK_LOG(error) << "Error stopping all: " << response.error_message() + << response.error_details(); } } @@ -431,8 +431,8 @@ RobotClient::status RobotClient::get_machine_status() const { const grpc::Status response = impl_->stub_->GetMachineStatus(ctx, req, &resp); if (is_error_response(response)) { - VIAM_LOG(error) << "Error getting machine status: " << response.error_message() - << response.error_details(); + VIAM_SDK_LOG(error) << "Error getting machine status: " << response.error_message() + << response.error_details(); } switch (resp.state()) { case robot::v1::GetMachineStatusResponse_State_STATE_INITIALIZING: diff --git a/src/viam/sdk/tests/test_log.cpp b/src/viam/sdk/tests/test_log.cpp index ad1c69f3c..d550cb8d4 100644 --- a/src/viam/sdk/tests/test_log.cpp +++ b/src/viam/sdk/tests/test_log.cpp @@ -16,7 +16,7 @@ namespace sdktests { BOOST_AUTO_TEST_CASE(test_cout_logging) { cout_redirect redirect; - VIAM_LOG(info) << "log1"; + VIAM_SDK_LOG(info) << "log1"; using namespace std::string_literals; @@ -32,9 +32,9 @@ BOOST_AUTO_TEST_CASE(test_cout_logging) { BOOST_AUTO_TEST_CASE(test_global_filter) { cout_redirect redirect; - VIAM_LOG(info) << "info1"; - VIAM_LOG(error) << "error1"; - VIAM_LOG(trace) << "trace1"; // not logged + VIAM_SDK_LOG(info) << "info1"; + VIAM_SDK_LOG(error) << "error1"; + VIAM_SDK_LOG(trace) << "trace1"; // not logged auto& logger = sdk::LogManager::get(); @@ -42,18 +42,18 @@ BOOST_AUTO_TEST_CASE(test_global_filter) { logger.set_global_log_level(ll::trace); - VIAM_LOG(trace) << "trace2"; - VIAM_LOG(info) << "info2"; + VIAM_SDK_LOG(trace) << "trace2"; + VIAM_SDK_LOG(info) << "info2"; logger.set_global_log_level(ll::error); - VIAM_LOG(info) << "info3"; // not logged - VIAM_LOG(error) << "error2"; + VIAM_SDK_LOG(info) << "info3"; // not logged + VIAM_SDK_LOG(error) << "error2"; logger.set_global_log_level(ll::info); - VIAM_LOG(info) << "info4"; - VIAM_LOG(trace) << "trace3"; // once again not logged + VIAM_SDK_LOG(info) << "info4"; + VIAM_SDK_LOG(trace) << "trace3"; // once again not logged const std::string rec = redirect.os.str(); redirect.release(); From 22d29e3867ed5b2613842b23efbd77ef68a0bb0a Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 20 Mar 2025 14:09:18 -0400 Subject: [PATCH 75/86] disable fail-fast --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c7a7bf7d5..9f20772b8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,6 +14,7 @@ jobs: runs-on: ubuntu-latest container: ghcr.io/viamrobotics/cpp-base:bullseye-amd64 strategy: + fail-fast: false matrix: include: - BUILD_SHARED: ON From 2e9d0159cbc04f5da80a9c60d89d0aff8b39d1a3 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 3 Apr 2025 18:16:44 -0400 Subject: [PATCH 76/86] link boost log and log_setup in public libs --- src/viam/sdk/config/viam-cpp-sdk-libviamsdk.pc.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/viam/sdk/config/viam-cpp-sdk-libviamsdk.pc.in b/src/viam/sdk/config/viam-cpp-sdk-libviamsdk.pc.in index 005af602e..a042d0010 100644 --- a/src/viam/sdk/config/viam-cpp-sdk-libviamsdk.pc.in +++ b/src/viam/sdk/config/viam-cpp-sdk-libviamsdk.pc.in @@ -7,6 +7,5 @@ Description: @PROJECT_DESCRIPTION@ URL: @PROJECT_HOMEPAGE_URL@ Version: @PROJECT_VERSION@ Requires: grpc++ >= @VIAMCPPSDK_GRPCXX_VERSION@ protobuf >= @VIAMCPPSDK_PROTOBUF_VERSION@ @PROJECT_NAME@-libviamapi >= @PROJECT_VERSION@ -Libs: -L${libdir} -L@Boost_LIBRARY_DIRS@ -lviamsdk -lviam_rust_utils -Libs.private: -lboost_log-mt +Libs: -L${libdir} -L@Boost_LIBRARY_DIRS@ -lviamsdk -lviam_rust_utils -lboost_log -lboost_log_setup Cflags: -I${includedir} -I@Boost_INCLUDE_DIR@ From b8dcf7c330c4dfe383e26aed30271acf319eac54 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Thu, 3 Apr 2025 18:20:25 -0400 Subject: [PATCH 77/86] set boost log dyn link in test script --- etc/docker/tests/run_test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/docker/tests/run_test.sh b/etc/docker/tests/run_test.sh index 6ac4702e8..f9418de3a 100755 --- a/etc/docker/tests/run_test.sh +++ b/etc/docker/tests/run_test.sh @@ -34,7 +34,7 @@ popd if [ ${BUILD_SHARED} = "ON" ] then pushd pkg-config - PKG_CONFIG_PATH=${INSTALL_DIR}/lib/pkgconfig make all + PKG_CONFIG_PATH=${INSTALL_DIR}/lib/pkgconfig CXXFLAGS="-DBOOST_LOG_DYN_LINK" make all run_module popd fi From f6c21ff5a7da751f4c8029c716fa61cb475af955 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 4 Apr 2025 10:43:43 -0400 Subject: [PATCH 78/86] clean up example camera and use logging instead of cout --- src/viam/examples/camera/example_camera.cpp | 155 +++++++++----------- 1 file changed, 69 insertions(+), 86 deletions(-) diff --git a/src/viam/examples/camera/example_camera.cpp b/src/viam/examples/camera/example_camera.cpp index d1eb9b80c..5124f0ee9 100644 --- a/src/viam/examples/camera/example_camera.cpp +++ b/src/viam/examples/camera/example_camera.cpp @@ -5,97 +5,80 @@ #include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/camera.hpp> +#include <viam/sdk/log/logging.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> -int main() { - using std::cerr; - using std::cout; - using std::endl; +int main() try { namespace vs = ::viam::sdk; - try { - // Every Viam C++ SDK program must have one and only one Instance object which is created - // before - // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. - vs::Instance inst; - - // If you want to connect to a remote robot, this should be the url of the robot - // Ex: xxx.xxx.viam.cloud - std::string robot_address("localhost:8080"); - // If you want to connect to a remote robot, you need some authentication secret - // You can find this on app.viam.com - vs::Credentials credentials("", ""); - - vs::DialOptions dial_options; - - // If you have credentials, use this to pass them to the robot - // dial_options.credentials = credentials; - - // This is for an example. Care should be taken before exercising this option in production. - dial_options.set_allow_insecure_downgrade( - (credentials.type().empty() && credentials.payload().empty())); - - // Set the refresh interval of the robot (in seconds) (0 = auto refresh) and the dial - // options - vs::Options options = vs::Options(1, dial_options); - - std::shared_ptr<vs::RobotClient> robot; - try { - robot = vs::RobotClient::at_address(robot_address, options); - cout << "Successfully connected to the robot" << endl; - } catch (const std::exception& e) { - cerr << "Failed to connect to the robot. Exiting." << endl; - throw; - } - - std::vector<vs::Name> resource_names = robot->resource_names(); - - cout << "Resources of the robot:" << endl; - for (const auto& resource : resource_names) { - cout << " - " << resource.name() << " (" << resource.api().resource_subtype() << ")" - << endl; - } - - std::string camera_name("camera1"); - - cout << "Getting camera: " << camera_name << endl; - std::shared_ptr<vs::Camera> camera; - try { - camera = robot->resource_by_name<vs::Camera>(camera_name); - } catch (const std::exception& e) { - cerr << "Failed to find " << camera_name << ". Exiting." << endl; - throw; - } - vs::Camera::properties props = camera->get_properties(); - vs::Camera::intrinsic_parameters intrinsics = props.intrinsic_parameters; - cout << "Image dimensions: " << intrinsics.width_px << " x " << intrinsics.height_px - << endl; - - std::string output_file("img.png"); - std::string image_mime_type("image/png"); - - cout << "Getting image from camera " << endl; - vs::Camera::raw_image img = camera->get_image(image_mime_type); - cout << "Got image of mime type: " << img.mime_type << endl; - - cout << "Getting and saving image to " << output_file << endl; - std::ofstream fout; - fout.open(output_file, std::ios::binary | std::ios::out); - if (fout.fail()) { - throw std::runtime_error("Failed to open output file " + output_file); - } - fout.write(reinterpret_cast<char*>(img.bytes.data()), img.bytes.size()); - fout.close(); - if (fout.fail()) { - throw std::runtime_error("Failed to write and close output file " + output_file); - } - } catch (const std::exception& ex) { - cerr << "Program failed. Exception: " << std::string(ex.what()) << endl; - return EXIT_FAILURE; - } catch (...) { - cerr << "Program failed without exception message." << endl; - return EXIT_FAILURE; + // Every Viam C++ SDK program must have one and only one Instance object which is created + // before + // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. + vs::Instance inst; + + // If you want to connect to a remote robot, this should be the url of the robot + // Ex: xxx.xxx.viam.cloud + std::string robot_address("localhost:8080"); + // If you want to connect to a remote robot, you need some authentication secret + // You can find this on app.viam.com + vs::Credentials credentials("", ""); + + vs::DialOptions dial_options; + + // If you have credentials, use this to pass them to the robot + // dial_options.credentials = credentials; + + // This is for an example. Care should be taken before exercising this option in production. + dial_options.set_allow_insecure_downgrade( + (credentials.type().empty() && credentials.payload().empty())); + + // Set the refresh interval of the robot (in seconds) (0 = auto refresh) and the dial + // options + vs::Options options = vs::Options(1, dial_options); + + std::shared_ptr<vs::RobotClient> robot = vs::RobotClient::at_address(robot_address, options); + VIAM_SDK_LOG(info) << "Successfully connected to the robot"; + + std::vector<vs::Name> resource_names = robot->resource_names(); + + VIAM_SDK_LOG(info) << "Resources of the robot:"; + for (const auto& resource : resource_names) { + VIAM_SDK_LOG(info) << " - " << resource.name() << " (" << resource.api().resource_subtype() + << ")"; } + std::string camera_name("camera1"); + + VIAM_SDK_LOG(info) << "Getting camera: " << camera_name; + std::shared_ptr<vs::Camera> camera = robot->resource_by_name<vs::Camera>(camera_name); + + vs::Camera::properties props = camera->get_properties(); + vs::Camera::intrinsic_parameters intrinsics = props.intrinsic_parameters; + VIAM_SDK_LOG(info) << "Image dimensions: " << intrinsics.width_px << " x " + << intrinsics.height_px; + + std::string output_file("img.png"); + std::string image_mime_type("image/png"); + + VIAM_SDK_LOG(info) << "Getting image from camera "; + + vs::Camera::raw_image img = camera->get_image(image_mime_type); + + VIAM_SDK_LOG(info) << "Got image of mime type: " << img.mime_type; + + VIAM_SDK_LOG(info) << "Getting and saving image to " << output_file; + + std::ofstream fout; + + // Operations on the ofstream will throw on failure. + fout.exceptions(std::ofstream::failbit); + fout.open(output_file, std::ios::binary | std::ios::out); + + fout.write(reinterpret_cast<char*>(img.bytes.data()), img.bytes.size()); + fout.close(); + return EXIT_SUCCESS; +} catch (const std::exception& ex) { + std::cerr << "Program failed. Exception: " << std::string(ex.what()) << "\n"; + return EXIT_FAILURE; } From ac25b4ebc2c589fe7b6331d7b158d72b1dd1004b Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 4 Apr 2025 13:58:27 -0400 Subject: [PATCH 79/86] update example code to use logging --- src/viam/examples/dial/example_dial.cpp | 7 +- .../dial_api_key/example_dial_api_key.cpp | 4 +- .../example_audio_classification_client.cpp | 7 +- src/viam/examples/modules/complex/client.cpp | 38 ++-- src/viam/examples/modules/simple/client.cpp | 15 +- src/viam/examples/modules/tflite/main.cpp | 8 +- src/viam/examples/motor/example_motor.cpp | 182 ++++++++---------- 7 files changed, 126 insertions(+), 135 deletions(-) diff --git a/src/viam/examples/dial/example_dial.cpp b/src/viam/examples/dial/example_dial.cpp index f39522c26..60c052fe1 100644 --- a/src/viam/examples/dial/example_dial.cpp +++ b/src/viam/examples/dial/example_dial.cpp @@ -11,6 +11,7 @@ #include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/generic.hpp> +#include <viam/sdk/log/logging.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -36,15 +37,15 @@ int main() { // ensure we can query resources std::vector<Name> resource_names = robot->resource_names(); - std::cout << "Resources" << std::endl; + VIAM_SDK_LOG(info) << "Resources:"; for (const Name& resource : resource_names) { - std::cout << "\t" << resource << "\n"; + VIAM_SDK_LOG(info) << resource; } // ensure we can create clients to the robot auto gc = robot->resource_by_name<GenericComponent>("generic1"); if (gc) { - std::cout << "got generic component client named " << gc->name() << std::endl; + VIAM_SDK_LOG(info) << "got generic component client named " << gc->name(); } return EXIT_SUCCESS; diff --git a/src/viam/examples/dial_api_key/example_dial_api_key.cpp b/src/viam/examples/dial_api_key/example_dial_api_key.cpp index b723e4227..850fe0dc9 100644 --- a/src/viam/examples/dial_api_key/example_dial_api_key.cpp +++ b/src/viam/examples/dial_api_key/example_dial_api_key.cpp @@ -50,9 +50,9 @@ int main(int argc, char* argv[]) { // ensure we can query resources std::vector<Name> resource_names = robot->resource_names(); - std::cout << "Resources" << std::endl; + VIAM_SDK_LOG(info) << "Resources:"; for (const Name& resource : resource_names) { - std::cout << "\t" << resource << "\n"; + VIAM_SDK_LOG(info) << resource; } return EXIT_SUCCESS; diff --git a/src/viam/examples/mlmodel/example_audio_classification_client.cpp b/src/viam/examples/mlmodel/example_audio_classification_client.cpp index 6be570449..a1d32b9c0 100644 --- a/src/viam/examples/mlmodel/example_audio_classification_client.cpp +++ b/src/viam/examples/mlmodel/example_audio_classification_client.cpp @@ -401,14 +401,11 @@ int main(int argc, char* argv[]) try { return EXIT_SUCCESS; } } catch (const std::exception& ex) { - std::cout << argv[0] << ": " + std::cerr << argv[0] << ": " << "Failed: a std::exception was thrown: `" << ex.what() << "``" << std::endl; return EXIT_FAILURE; -} catch (const std::string& ex) { - std::cout << argv[0] << ": " - << "Failed: a std::string was thrown: `" << ex << "``" << std::endl; } catch (...) { - std::cout << argv[0] << ": " + std::cerr << argv[0] << ": " << "Failed: an unknown exception was thrown" << std::endl; return EXIT_FAILURE; } diff --git a/src/viam/examples/modules/complex/client.cpp b/src/viam/examples/modules/complex/client.cpp index 4c26f055f..28bd451dc 100644 --- a/src/viam/examples/modules/complex/client.cpp +++ b/src/viam/examples/modules/complex/client.cpp @@ -13,6 +13,7 @@ #include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/motor.hpp> +#include <viam/sdk/log/logging.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -48,54 +49,61 @@ int main() { // Connect to robot. std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options); // Print resources. - std::cout << "Resources" << std::endl; + VIAM_SDK_LOG(info) << "Resources:"; std::vector<Name> resource_names = robot->resource_names(); for (const Name& resource : resource_names) { - std::cout << "\t" << resource << "\n"; + VIAM_SDK_LOG(info) << resource; } // Exercise Gizmo methods. auto gc = robot->resource_by_name<Gizmo>("gizmo1"); if (!gc) { - std::cerr << "could not get 'gizmo1' resource from robot" << std::endl; + VIAM_SDK_LOG(error) << "could not get 'gizmo1' resource from robot" << std::endl; return EXIT_FAILURE; } + bool do_one_ret = gc->do_one("arg1"); - std::cout << "gizmo1 do_one returned: " << do_one_ret << std::endl; + VIAM_SDK_LOG(info) << "gizmo1 do_one returned: " << do_one_ret; + bool do_one_client_stream_ret = gc->do_one_client_stream({"arg1", "arg1", "arg1"}); - std::cout << "gizmo1 do_one_client_stream returned: " << do_one_client_stream_ret << std::endl; + VIAM_SDK_LOG(info) << "gizmo1 do_one_client_stream returned: " << do_one_client_stream_ret; + std::string do_two_ret = gc->do_two(false); - std::cout << "gizmo1 do_two returned: " << do_two_ret << std::endl; + VIAM_SDK_LOG(info) << "gizmo1 do_two returned: " << do_two_ret; + std::vector<bool> do_one_server_stream_ret = gc->do_one_server_stream("arg1"); - std::cout << "gizmo1 do_one_server_stream returned: " << std::endl; + VIAM_SDK_LOG(info) << "gizmo1 do_one_server_stream returned: "; for (bool ret : do_one_server_stream_ret) { - std::cout << '\t' << ret << std::endl; + VIAM_SDK_LOG(info) << ret; } + std::vector<bool> do_one_bidi_stream_ret = gc->do_one_bidi_stream({"arg1", "arg2", "arg3"}); - std::cout << "gizmo1 do_one_bidi_stream returned: " << std::endl; + VIAM_SDK_LOG(info) << "gizmo1 do_one_bidi_stream returned: "; for (bool ret : do_one_bidi_stream_ret) { - std::cout << '\t' << ret << std::endl; + VIAM_SDK_LOG(info) << ret; } // Exercise Summation methods. auto sc = robot->resource_by_name<Summation>("mysum1"); if (!sc) { - std::cerr << "could not get 'mysum1' resource from robot" << std::endl; + VIAM_SDK_LOG(error) << "could not get 'mysum1' resource from robot"; return EXIT_FAILURE; } + double sum = sc->sum({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); - std::cout << "mysum1 sum of numbers [0, 10) is: " << sum << std::endl; + VIAM_SDK_LOG(info) << "mysum1 sum of numbers [0, 10) is: " << sum; // Exercise a Base method. auto mc = robot->resource_by_name<Motor>("motor1"); if (!mc) { - std::cerr << "could not get 'motor1' resource from robot" << std::endl; + VIAM_SDK_LOG(error) << "could not get 'motor1' resource from robot"; return EXIT_FAILURE; } + if (mc->is_moving()) { - std::cout << "motor1 is moving" << std::endl; + VIAM_SDK_LOG(info) << "motor1 is moving"; } else { - std::cout << "motor1 is not moving" << std::endl; + VIAM_SDK_LOG(info) << "motor1 is not moving"; } return EXIT_SUCCESS; diff --git a/src/viam/examples/modules/simple/client.cpp b/src/viam/examples/modules/simple/client.cpp index f08410336..75ca90e34 100644 --- a/src/viam/examples/modules/simple/client.cpp +++ b/src/viam/examples/modules/simple/client.cpp @@ -5,6 +5,7 @@ #include <viam/sdk/common/instance.hpp> #include <viam/sdk/common/proto_value.hpp> #include <viam/sdk/components/sensor.hpp> +#include <viam/sdk/log/logging.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -32,16 +33,16 @@ int main() { std::shared_ptr<RobotClient> robot = RobotClient::at_address(address, options); // Print resources - std::cout << "Resources\n"; + VIAM_SDK_LOG(info) << "Resources"; std::vector<Name> resource_names = robot->resource_names(); for (const Name& resource : resource_names) { - std::cout << "\t" << resource << "\n"; + VIAM_SDK_LOG(info) << resource; } // Exercise sensor methods auto sensor = robot->resource_by_name<Sensor>("mysensor"); if (!sensor) { - std::cerr << "could not get 'mysensor' resource from robot\n"; + VIAM_SDK_LOG(error) << "could not get 'mysensor' resource from robot"; return EXIT_FAILURE; } @@ -49,7 +50,7 @@ int main() { ProtoStruct resp = sensor->do_command(command); if (command != resp) { - std::cerr << "Got unexpected result from 'mysensor'\n"; + VIAM_SDK_LOG(error) << "Got unexpected result from 'mysensor'"; return EXIT_FAILURE; } @@ -57,15 +58,15 @@ int main() { auto itr = readings.find("signal"); if (itr == readings.end()) { - std::cerr << "Expected signal not found in sensor readings\n"; + VIAM_SDK_LOG(error) << "Expected signal not found in sensor readings"; return EXIT_FAILURE; } const double* signal = itr->second.get<double>(); if (signal) { - std::cout << "\t" << itr->first << ": " << *signal << "\n"; + VIAM_SDK_LOG(info) << itr->first << ": " << *signal; } else { - std::cerr << "Unexpected value type for sensor reading\n"; + VIAM_SDK_LOG(error) << "Unexpected value type for sensor reading"; return EXIT_FAILURE; } diff --git a/src/viam/examples/modules/tflite/main.cpp b/src/viam/examples/modules/tflite/main.cpp index 65ca8c191..4bebd97d2 100644 --- a/src/viam/examples/modules/tflite/main.cpp +++ b/src/viam/examples/modules/tflite/main.cpp @@ -757,10 +757,10 @@ int serve(const std::string& socket_path) try { return EXIT_SUCCESS; } catch (const std::exception& ex) { - std::cout << "ERROR: A std::exception was thrown from `serve`: " << ex.what() << std::endl; + std::cerr << "ERROR: A std::exception was thrown from `serve`: " << ex.what() << std::endl; return EXIT_FAILURE; } catch (...) { - std::cout << "ERROR: An unknown exception was thrown from `serve`" << std::endl; + std::cerr << "ERROR: An unknown exception was thrown from `serve`" << std::endl; return EXIT_FAILURE; } @@ -770,8 +770,8 @@ int main(int argc, char* argv[]) { const std::string usage = "usage: mlmodelservice_tflite /path/to/unix/socket"; if (argc < 2) { - std::cout << "ERROR: insufficient arguments\n"; - std::cout << usage << "\n"; + std::cerr << "ERROR: insufficient arguments\n"; + std::cerr << usage << "\n"; return EXIT_FAILURE; } diff --git a/src/viam/examples/motor/example_motor.cpp b/src/viam/examples/motor/example_motor.cpp index 3d5a640ef..4cc781f0f 100644 --- a/src/viam/examples/motor/example_motor.cpp +++ b/src/viam/examples/motor/example_motor.cpp @@ -8,6 +8,7 @@ #include <viam/sdk/common/instance.hpp> #include <viam/sdk/components/motor.hpp> +#include <viam/sdk/log/logging.hpp> #include <viam/sdk/robot/client.hpp> #include <viam/sdk/rpc/dial.hpp> @@ -15,116 +16,99 @@ void print_motor_position(std::shared_ptr<viam::sdk::Motor> motor) { // Whether the motor supports returning its position if (motor->get_properties().position_reporting) { // Position is measured in rotations (position is a typedef double) - std::cout << "Motor pos: " << motor->get_position() << std::endl; + VIAM_SDK_LOG(info) << "Motor pos: " << motor->get_position(); } else { - std::cout << "Motor position unavailable" << std::endl; + VIAM_SDK_LOG(info) << "Motor position unavailable"; } } -int main() { - using std::cerr; - using std::cout; - using std::endl; +int main() try { namespace vs = ::viam::sdk; - try { - // Every Viam C++ SDK program must have one and only one Instance object which is created - // before any other C++ SDK objects and stays alive until all Viam C++ SDK objects are - // destroyed. - vs::Instance inst; - - // If you want to connect to a remote robot, this should be the url of the robot - // Ex: xxx.xxx.viam.cloud - std::string robot_address("localhost:8080"); - // If you want to connect to a remote robot, you need some authentication secret - // You can find this on app.viam.com - vs::Credentials credentials("", ""); - - vs::DialOptions dial_options; - - // If you have credentials, use this to pass them to the robot - // dial_options.credentials = credentials; - - // This is for an example. Care should be taken before exercising this option in production. - dial_options.set_allow_insecure_downgrade( - (credentials.type().empty() && credentials.payload().empty())); - - // Set the refresh interval of the robot (in seconds) (0 = auto refresh) and the dial - // options - vs::Options options = vs::Options(1, dial_options); - - std::shared_ptr<vs::RobotClient> robot; - try { - robot = vs::RobotClient::at_address(robot_address, options); - cout << "Successfully connected to the robot" << endl; - } catch (const std::exception& e) { - cerr << "Failed to connect to the robot. Exiting." << endl; - throw; - } - - std::vector<vs::Name> resource_names = robot->resource_names(); - - cout << "Resources of the robot:" << endl; - for (const vs::Name& resource : resource_names) { - cout << resource << endl; - } - - std::string motor_name("motor1"); - - cout << "Getting motor: " << motor_name << endl; - std::shared_ptr<vs::Motor> motor; - try { - motor = robot->resource_by_name<vs::Motor>(motor_name); - } catch (const std::exception& e) { - cerr << "Failed to find " << motor_name << ". Exiting." << endl; - throw; - } - - // Motors are always turned off if there is no attached client so this is expected to be 0 - cout << "Motor power: " << motor->get_power_status().power_pct << endl; - cout << "Setting motor power to 50%" << endl; - motor->set_power(0.5); - cout << "Motor power: " << motor->get_power_status().power_pct << endl; + // Every Viam C++ SDK program must have one and only one Instance object which is created + // before any other C++ SDK objects and stays alive until all Viam C++ SDK objects are + // destroyed. + vs::Instance inst; - print_motor_position(motor); + // If you want to connect to a remote robot, this should be the url of the robot + // Ex: xxx.xxx.viam.cloud + std::string robot_address("localhost:8080"); + // If you want to connect to a remote robot, you need some authentication secret + // You can find this on app.viam.com + vs::Credentials credentials("", ""); - cout << "Moving motor by 0.5 rotations at 10rpm" << endl; - motor->go_for(10, 0.5); - print_motor_position(motor); - cout << "Moving motor back to starting location" << endl; - if (motor->get_properties().position_reporting) { - // More accurate - motor->go_to(10, 0); - } else { - // If position reporting is unavailable, we cannot call go_to - // but we can defer to reverting past actions - motor->go_for(10, -0.5); - } - print_motor_position(motor); - cout << "Moving motor forward for 2 seconds at 30rpm" << endl; - // With `revolutions`==0, the call will be non-blocking - // and the motor will rotate indefintely. - motor->go_for(30, 0); + vs::DialOptions dial_options; - print_motor_position(motor); + // If you have credentials, use this to pass them to the robot + // dial_options.credentials = credentials; + + // This is for an example. Care should be taken before exercising this option in production. + dial_options.set_allow_insecure_downgrade( + (credentials.type().empty() && credentials.payload().empty())); + + // Set the refresh interval of the robot (in seconds) (0 = auto refresh) and the dial + // options + vs::Options options = vs::Options(1, dial_options); + + std::shared_ptr<vs::RobotClient> robot = vs::RobotClient::at_address(robot_address, options); + VIAM_SDK_LOG(info) << "Successfully connected to the robot"; - // Wait for 2 seconds, print position every 0.5 seconds - for (int i = 0; i < 4; i++) { - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - print_motor_position(motor); - } - - // Explicitly stop the motor - cout << "Stopping motor" << endl; - motor->stop({}); - - } catch (const std::exception& ex) { - cerr << "Program failed. Exception: " << std::string(ex.what()) << endl; - return EXIT_FAILURE; - } catch (...) { - cerr << "Program failed without exception message." << endl; - return EXIT_FAILURE; + std::vector<vs::Name> resource_names = robot->resource_names(); + + VIAM_SDK_LOG(info) << "Resources of the robot:"; + for (const vs::Name& resource : resource_names) { + VIAM_SDK_LOG(info) << resource; } + std::string motor_name("motor1"); + + VIAM_SDK_LOG(info) << "Getting motor: " << motor_name; + std::shared_ptr<vs::Motor> motor = robot->resource_by_name<vs::Motor>(motor_name); + + // Motors are always turned off if there is no attached client so this is expected to be 0 + VIAM_SDK_LOG(info) << "Motor power: " << motor->get_power_status().power_pct; + VIAM_SDK_LOG(info) << "Setting motor power to 50%"; + motor->set_power(0.5); + VIAM_SDK_LOG(info) << "Motor power: " << motor->get_power_status().power_pct; + + print_motor_position(motor); + + VIAM_SDK_LOG(info) << "Moving motor by 0.5 rotations at 10rpm"; + motor->go_for(10, 0.5); + + print_motor_position(motor); + + VIAM_SDK_LOG(info) << "Moving motor back to starting location"; + if (motor->get_properties().position_reporting) { + // More accurate + motor->go_to(10, 0); + } else { + // If position reporting is unavailable, we cannot call go_to + // but we can defer to reverting past actions + motor->go_for(10, -0.5); + } + + print_motor_position(motor); + + VIAM_SDK_LOG(info) << "Moving motor forward for 2 seconds at 30rpm"; + // With `revolutions`==0, the call will be non-blocking + // and the motor will rotate indefintely. + motor->go_for(30, 0); + + print_motor_position(motor); + + // Wait for 2 seconds, print position every 0.5 seconds + for (int i = 0; i < 4; i++) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + print_motor_position(motor); + } + + // Explicitly stop the motor + VIAM_SDK_LOG(info) << "Stopping motor"; + motor->stop({}); + return EXIT_SUCCESS; +} catch (const std::exception& ex) { + std::cerr << "Program failed. Exception: " << std::string(ex.what()) << "\n"; + return EXIT_FAILURE; } From 04c92ce54006c2b884f436e3e332e49fd049dfeb Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Fri, 4 Apr 2025 14:56:17 -0400 Subject: [PATCH 80/86] add test and use set_global_resource_name --- .../example_audio_classification_client.cpp | 107 +++++++++--------- src/viam/sdk/log/logging.cpp | 5 + src/viam/sdk/log/logging.hpp | 3 + src/viam/sdk/tests/test_log.cpp | 17 +++ 4 files changed, 80 insertions(+), 52 deletions(-) diff --git a/src/viam/examples/mlmodel/example_audio_classification_client.cpp b/src/viam/examples/mlmodel/example_audio_classification_client.cpp index a1d32b9c0..51e5731ea 100644 --- a/src/viam/examples/mlmodel/example_audio_classification_client.cpp +++ b/src/viam/examples/mlmodel/example_audio_classification_client.cpp @@ -83,6 +83,18 @@ int main(int argc, char* argv[]) try { // any other C++ SDK objects and stays alive until all Viam C++ SDK objects are destroyed. viam::sdk::Instance inst; + // By default, log messages with VIAM_SDK_LOG have "Viam C++ SDK" as the resource name. + // Here we override it with the name of the executable, trimming the leading path if present. + + std::string exe_name{argv[0]}; + + const auto last_slash_pos = exe_name.find_last_of('/'); + if (last_slash_pos != std::string::npos) { + exe_name = exe_name.substr(last_slash_pos); + } + + viam::sdk::LogManager::get().set_global_resource_name(exe_name); + // Build up our command line options. The example operates in two // modes. In the "--generate" mode, it takes command line // parameters needed to satisfy the interpolation points in the @@ -168,35 +180,33 @@ int main(int argc, char* argv[]) try { if (opt_generating) { // Validate that we have the right options for generation. if (opt_robot_host || opt_api_key || opt_api_key_id) { - std::cout << argv[0] - << ": With `--generate`, do not provide `--robot-{host,api-key,api-key-id}`" - << std::endl; + VIAM_SDK_LOG(error) + << "With `--generate`, do not provide `--robot-{host,api-key,api-key-id}`"; return EXIT_FAILURE; } if (!opt_model_path) { - std::cout << argv[0] << ": With `--generate`, a `--model-path` is required" - << std::endl; + VIAM_SDK_LOG(error) << "With `--generate`, a `--model-path` is required"; return EXIT_FAILURE; } + const bf::path model_path(opt_model_path.get()); if (!bf::is_regular_file(model_path)) { - std::cout << argv[0] << ": The path `" << model_path.c_str() - << "` provided for `--model-path` is not an existing regular file" - << std::endl; + VIAM_SDK_LOG(error) << "The path `" << model_path.c_str() + << "` provided for `--model-path` is not an existing regular file"; return EXIT_FAILURE; } if (!opt_tflite_module_path) { - std::cout << argv[0] << ": With `--generate`, a `--tflite-module-path` is required" - << std::endl; + VIAM_SDK_LOG(error) << "With `--generate`, a `--tflite-module-path` is required"; return EXIT_FAILURE; } + const bf::path tflite_module_path(opt_tflite_module_path.get()); if (!bf::is_regular_file(tflite_module_path)) { - std::cout << argv[0] << ": The path `" << tflite_module_path.c_str() - << "` provided for `--tflite-module-path` is not an existing regular file" - << std::endl; + VIAM_SDK_LOG(error) + << "The path `" << tflite_module_path.c_str() + << "` provided for `--tflite-module-path` is not an existing regular file"; return EXIT_FAILURE; } @@ -207,28 +217,25 @@ int main(int argc, char* argv[]) try { const auto config = boost::format(kRobotConfigTemplate) % bf::absolute(model_path).c_str() % bf::absolute(tflite_module_path).c_str(); - std::cout << config << std::endl; + VIAM_SDK_LOG(info) << config << std::endl; } else { // Validate that we have the right options for classification mode. if (opt_model_path || opt_tflite_module_path) { - std::cout << argv[0] << ": Without `--generate`, do not provide `--*path*` arguments" - << std::endl; + VIAM_SDK_LOG(error) << "Without `--generate`, do not provide `--*path*` arguments"; return EXIT_FAILURE; } if (!opt_robot_host) { - std::cout << argv[0] - << ": The `--robot-host` argument is required when connecting to a robot" - << std::endl; + VIAM_SDK_LOG(error) + << "The `--robot-host` argument is required when connecting to a robot"; return EXIT_FAILURE; } if (!opt_api_key || !opt_api_key_id) { - std::cout << argv[0] - << ": The `--robot-api-key` and the `--robot-api-key-id` argument are " - "required when connecting to a robot" - << std::endl; + VIAM_SDK_LOG(error) + << "The `--robot-api-key` and the `--robot-api-key-id` argument are " + "required when connecting to a robot"; return EXIT_FAILURE; } @@ -248,10 +255,9 @@ int main(int argc, char* argv[]) try { auto yamnet_service = robot->resource_by_name<vsdk::MLModelService>("yamnet_classification_tflite"); if (!yamnet_service) { - std::cout << argv[0] << ": " - << "Failed: did not find the `yamnet_classification_tflite` resource, cannot " - "continue" - << std::endl; + VIAM_SDK_LOG(error) + << " did not find the `yamnet_classification_tflite` resource, cannot " + "continue"; return EXIT_FAILURE; } @@ -296,8 +302,7 @@ int main(int argc, char* argv[]) try { // the robot configuration. auto categories = result->find("categories"); if (categories == result->end()) { - std::cout << argv[0] << ": " - << "Failed: a `categories` tensor was not returned" << std::endl; + VIAM_SDK_LOG(error) << "A `categories` tensor was not returned"; return EXIT_FAILURE; } @@ -311,10 +316,8 @@ int main(int argc, char* argv[]) try { const auto* const categories_float = boost::get<vsdk::MLModelService::tensor_view<float>>(&categories->second); if (!categories_float) { - std::cout - << argv[0] << ": " - << "Failed: a `categories` tensor was returned, but it was not of type `float`" - << std::endl; + VIAM_SDK_LOG(error) + << "A `categories` tensor was returned, but it was not of type `float`"; return EXIT_FAILURE; } @@ -323,23 +326,23 @@ int main(int argc, char* argv[]) try { // results and print out the label and score. if (!opt_model_label_path) { for (const auto& val : *categories_float) { - std::cout << val << std::endl; + VIAM_SDK_LOG(info) << val; } } else { // Ensure that the label path is something we can actually read from. const bf::path model_label_path(opt_model_label_path.get()); if (!bf::is_regular_file(model_label_path)) { - std::cout << argv[0] << ": Failed: The path `" << model_label_path.c_str() - << "` provided for `--model-label-path` is not an existing regular file" - << std::endl; + VIAM_SDK_LOG(error) + << "The path `" << model_label_path.c_str() + << "` provided for `--model-label-path` is not an existing regular file"; return EXIT_FAILURE; } // Open the labels file, or bail. std::ifstream labels_stream(model_label_path.c_str()); if (!labels_stream) { - std::cout << argv[0] << ": Failed: Unable to open label path `" - << model_label_path.c_str() << "`" << std::endl; + VIAM_SDK_LOG(error) + << "Unable to open label path `" << model_label_path.c_str() << "`"; return EXIT_FAILURE; } @@ -353,9 +356,8 @@ int main(int argc, char* argv[]) try { // If the tensor size doesn't match the labels file size, then the labels file // is probably incorrect. if (categories_float->size() != labels.size()) { - std::cout << argv[0] - << ": Failed: Size mismatch between category scores and label files" - << std::endl; + VIAM_SDK_LOG(error) + << "Size mismatch between category scores and label files" << std::endl; return EXIT_FAILURE; } @@ -364,10 +366,12 @@ int main(int argc, char* argv[]) try { const std::string* label; float score; }; + std::vector<scored_label> scored_labels; for (size_t i = 0; i != labels.size(); ++i) { scored_labels.push_back({&labels[i], (*categories_float)[i]}); } + std::sort(begin(scored_labels), end(scored_labels), [](const auto& l, const auto& r) { return l.score > r.score; }); @@ -375,37 +379,36 @@ int main(int argc, char* argv[]) try { // Print out the top 5 (or fewer) label/score pairs. for (size_t i = 0; i != std::min(5UL, scored_labels.size()); ++i) { // TODO: Avoid hardcoding the width here. - std::cout << boost::format("%1%: %2% %|40t|%3%\n") % i % *scored_labels[i].label % - scored_labels[i].score; + VIAM_SDK_LOG(info) << boost::format("%1%: %2% %|40t|%3%\n") % i % + *scored_labels[i].label % scored_labels[i].score; } - std::cout.flush(); } // Run 100 rounds of inference, accumulate some descriptive // statistics, and report them. - std::cout << "\nMeasuring inference latency ...\n"; + VIAM_SDK_LOG(info) << "\nMeasuring inference latency ..."; bacc::accumulator_set<double, bacc::stats<bacc::tag::mean, bacc::tag::moment<2>>> accumulator; + for (std::size_t i = 0; i != 100; ++i) { const auto start = std::chrono::steady_clock::now(); static_cast<void>(yamnet_service->infer(inputs)); const auto finish = std::chrono::steady_clock::now(); const std::chrono::duration<double> elapsed = finish - start; - ; accumulator(elapsed.count()); } - std::cout << "Inference latency (seconds), Mean: " << bacc::mean(accumulator) << std::endl; - std::cout << "Inference latency (seconds), Var : " << bacc::moment<2>(accumulator) - << std::endl; + + VIAM_SDK_LOG(info) << "Inference latency (seconds), Mean: " << bacc::mean(accumulator); + VIAM_SDK_LOG(info) << "Inference latency (seconds), Var : " << bacc::moment<2>(accumulator); return EXIT_SUCCESS; } } catch (const std::exception& ex) { std::cerr << argv[0] << ": " - << "Failed: a std::exception was thrown: `" << ex.what() << "``" << std::endl; + << "Failed: a std::exception was thrown: `" << ex.what() << "``\n"; return EXIT_FAILURE; } catch (...) { std::cerr << argv[0] << ": " - << "Failed: an unknown exception was thrown" << std::endl; + << "Failed: an unknown exception was thrown\n"; return EXIT_FAILURE; } diff --git a/src/viam/sdk/log/logging.cpp b/src/viam/sdk/log/logging.cpp index 024a622ca..0c8c7ec2a 100644 --- a/src/viam/sdk/log/logging.cpp +++ b/src/viam/sdk/log/logging.cpp @@ -91,6 +91,11 @@ LogManager& LogManager::get() { return result; } +void LogManager::set_global_resource_name(std::string name) { + sdk_logger_.channel(std::move(name)); + VIAM_SDK_LOG(debug) << "Overrode global resource name"; +} + LogSource& LogManager::global_logger() { return sdk_logger_; } diff --git a/src/viam/sdk/log/logging.hpp b/src/viam/sdk/log/logging.hpp index 93bdaa044..11004a302 100644 --- a/src/viam/sdk/log/logging.hpp +++ b/src/viam/sdk/log/logging.hpp @@ -69,6 +69,9 @@ class LogManager { /// This is the only way to access the logger. static LogManager& get(); + /// @brief Override the channel name of general log messages not originating from resources. + void set_global_resource_name(std::string); + /// @brief Set the global logger severity. void set_global_log_level(log_level); diff --git a/src/viam/sdk/tests/test_log.cpp b/src/viam/sdk/tests/test_log.cpp index d550cb8d4..da52b3733 100644 --- a/src/viam/sdk/tests/test_log.cpp +++ b/src/viam/sdk/tests/test_log.cpp @@ -29,6 +29,23 @@ BOOST_AUTO_TEST_CASE(test_cout_logging) { } } +BOOST_AUTO_TEST_CASE(test_global_name) { + cout_redirect redirect; + + sdk::LogManager::get().set_global_resource_name("My Channel"); + + VIAM_SDK_LOG(info) << "after"; + + const std::string rec = redirect.os.str(); + redirect.release(); + + for (const char* s : {"My Channel", "after"}) { + BOOST_CHECK(rec.find(s) != std::string::npos); + } + + BOOST_CHECK(rec.find(sdk::global_resource_name()) == std::string::npos); +} + BOOST_AUTO_TEST_CASE(test_global_filter) { cout_redirect redirect; From 9297062abf2c0c452c2219c2a9946783f8e5a948 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Mon, 7 Apr 2025 11:07:08 -0400 Subject: [PATCH 81/86] silence const warnings --- src/viam/sdk/log/logging.cpp | 4 ++-- src/viam/sdk/log/logging.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/viam/sdk/log/logging.cpp b/src/viam/sdk/log/logging.cpp index 0c8c7ec2a..910636e80 100644 --- a/src/viam/sdk/log/logging.cpp +++ b/src/viam/sdk/log/logging.cpp @@ -91,8 +91,8 @@ LogManager& LogManager::get() { return result; } -void LogManager::set_global_resource_name(std::string name) { - sdk_logger_.channel(std::move(name)); +void LogManager::set_global_resource_name(const std::string& name) { + sdk_logger_.channel(name); VIAM_SDK_LOG(debug) << "Overrode global resource name"; } diff --git a/src/viam/sdk/log/logging.hpp b/src/viam/sdk/log/logging.hpp index 11004a302..9103b2033 100644 --- a/src/viam/sdk/log/logging.hpp +++ b/src/viam/sdk/log/logging.hpp @@ -70,7 +70,7 @@ class LogManager { static LogManager& get(); /// @brief Override the channel name of general log messages not originating from resources. - void set_global_resource_name(std::string); + void set_global_resource_name(const std::string& name); /// @brief Set the global logger severity. void set_global_log_level(log_level); From b1aa44b430a7ce1fe49073617de24960e62b2163 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:09:00 -0400 Subject: [PATCH 82/86] add remark on logging enums --- src/viam/sdk/log/logging.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/viam/sdk/log/logging.hpp b/src/viam/sdk/log/logging.hpp index 9103b2033..18b33200d 100644 --- a/src/viam/sdk/log/logging.hpp +++ b/src/viam/sdk/log/logging.hpp @@ -24,6 +24,9 @@ namespace sdk { /// @brief Severity levels for the logger. /// @ingroup Log +/// @remark Our enums are usually prefixed with k_, but these values are meant to be used without +/// namespace qualification in the log macros, eg `VIAM_SDK_LOG(info)` instead of +/// `VIAM_SDK_LOG(k_info)`. enum class log_level : std::int8_t { trace = -2, debug = -1, From 6018b945b5688d40f2e693234f35ab6420c9b32a Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:15:48 -0400 Subject: [PATCH 83/86] add explanatory comment --- src/viam/sdk/log/private/log_backend.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/viam/sdk/log/private/log_backend.cpp b/src/viam/sdk/log/private/log_backend.cpp index 6e917adc5..00287c797 100644 --- a/src/viam/sdk/log/private/log_backend.cpp +++ b/src/viam/sdk/log/private/log_backend.cpp @@ -7,6 +7,8 @@ namespace viam { namespace sdk { namespace impl { +// The following code was copy-pasted from the boost mailing list +// https://lists.boost.org/boost-commit/2009/04/15209.php time_pt ptime_convert(const boost::posix_time::ptime& from) { namespace posix_time = boost::posix_time; From bc5f1652a4edb53bbb623004a93e546a5ed82f6c Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:51:30 -0400 Subject: [PATCH 84/86] format file/line into rdk log message --- src/viam/sdk/log/private/log_backend.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/viam/sdk/log/private/log_backend.cpp b/src/viam/sdk/log/private/log_backend.cpp index 00287c797..cde30a506 100644 --- a/src/viam/sdk/log/private/log_backend.cpp +++ b/src/viam/sdk/log/private/log_backend.cpp @@ -20,9 +20,14 @@ time_pt ptime_convert(const boost::posix_time::ptime& from) { } void LogBackend::consume(const boost::log::record_view& rec) const { + std::ostringstream os; + + os << "[" << *rec[attr_file_type{}] << ":" << rec[attr_line_type{}] << "] " + << *rec[boost::log::expressions::smessage]; + parent->log(*rec[attr_channel_type{}], to_string(*rec[attr_sev_type{}]), - *rec[boost::log::expressions::smessage], + os.str(), ptime_convert(*rec[attr_time_type{}])); } From 82f710479be4f4cec93c029e8526773607ce0185 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:58:58 -0400 Subject: [PATCH 85/86] document use of boost log --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 90eb9419c..e754f6bc6 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,15 @@ above) should resolve them. And please file a bug report! We will endeavor to be as responsive as possible, and resolve issues as quickly as possible. +## A note on logging + +Users should only interact with logging via the macros, classes, and functions in +[`viam/sdk/log/logging.hpp`](src/viam/sdk/log/logging.hpp). Logging is +implemented using Boost.Log, but this is an implementation detail subject +to change without warning. In particular, using Boost.Log macros such as +`BOOST_LOG_TRIVIAL` or `BOOST_LOG_SEV` is undefined behavior which will likely +fail to output log messages. + ## License Copyright 2022 Viam Inc. From 2fa08609a13c4a09d86407089992a7528988f910 Mon Sep 17 00:00:00 2001 From: Lia Stratopoulos <167905060+lia-viam@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:59:07 -0400 Subject: [PATCH 86/86] remove period --- src/viam/sdk/log/logging.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/viam/sdk/log/logging.hpp b/src/viam/sdk/log/logging.hpp index 18b33200d..aa86c40d2 100644 --- a/src/viam/sdk/log/logging.hpp +++ b/src/viam/sdk/log/logging.hpp @@ -20,7 +20,7 @@ namespace viam { namespace sdk { -/// @defgroup Log Classes related to logging. +/// @defgroup Log Classes related to logging /// @brief Severity levels for the logger. /// @ingroup Log