Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added LogHandler, this enables the possibility to change the behavior when logging messages with this library. #40

Merged
merged 2 commits into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ add_library(urcl SHARED
src/ur/dashboard_client.cpp
src/ur/tool_communication.cpp
src/rtde/rtde_writer.cpp
src/default_log_handler.cpp
src/log.cpp
)
add_library(ur_client_library::urcl ALIAS urcl)
target_compile_options(urcl PRIVATE -Wall -Wextra -Wno-unused-parameter)
Expand Down
94 changes: 85 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ robotic manipulators.
[boost](https://github.com/UniversalRobots/Universal_Robots_Client_Library/tree/boost) branch
instead that requires the boost library.
For the C++17 features, please use those minimum compiler versions:

| Compiler | min. version |
|-----------|--------------|
| **GCC** | 7 |
| **Clang** | 7 |


## Build instructions
### Plain cmake
Expand Down Expand Up @@ -301,11 +301,87 @@ As this library was originally designed to be included into a ROS driver but als
standalone library, it uses custom logging macros instead of direct `printf` or `std::cout`
statements.

These logging macros will either be translated into `printf` statements or logging commands of
[`console_bridge`](https://github.com/ros/console_bridge) if `console_bridge` is found on the system
during the cmake run. In this case, the define `ROS_BUILD` will be set. When built inside a catkin
workspace, logging commands are automatically translated into ROS logging commands.
The macro based interface is by default using the [`DefaultLogHandler`](include/ur_client_library/default_log_handler.h)
to print the logging messages as `printf` statements. It is possible to define your own log handler
to change the behavior, [see create new log handler](#Create-new-log-handler) on how to.

### Change logging level
Make sure to set the logging level in your application, as by default only messages of level
WARNING or higher will be printed. See below for an example:
```c++
#include "ur_client_library/log.h"

int main(int argc, char* argv[])
{
urcl::setLogLevel(urcl::LogLevel::DEBUG);

URCL_LOG_DEBUG("Logging debug message");
return 0;
}
```

### Create new log handler
The logger comes with an interface [`LogHandler`](include/ur_client_library/log.h), which can be
used to implement your own log handler for messages logged with this library. This can be done by
inheriting from the `LogHandler class`.

If you want to create a new log handler in your application, you can use below example as
inspiration:

```c++
#include "ur_client_library/log.h"
#include <iostream>

class MyLogHandler : public urcl::LogHandler
{
public:
MyLogHandler() = default;

void log(const char* file, int line, urcl::LogLevel loglevel, const char* log) override
{
switch (loglevel)
{
case urcl::LogLevel::INFO:
std::cout << "INFO " << file << " " << line << ": " << log << std::endl;
break;
case urcl::LogLevel::DEBUG:
std::cout << "DEBUG " << file << " " << line << ": " << log << std::endl;
break;
case urcl::LogLevel::WARN:
std::cout << "WARN " << file << " " << line << ": " << log << std::endl;
break;
case urcl::LogLevel::ERROR:
std::cout << "ERROR " << file << " " << line << ": " << log << std::endl;
break;
case urcl::LogLevel::FATAL:
std::cout << "ERROR " << file << " " << line << ": " << log << std::endl;
break;
default:
break;
}
}
};

int main(int argc, char* argv[])
{
urcl::setLogLevel(urcl::LogLevel::DEBUG);
std::unique_ptr<MyLogHandler> log_handler(new MyLogHandler);
urcl::registerLogHandler(std::move(log_handler));

URCL_LOG_DEBUG("logging debug message");
URCL_LOG_INFO("logging info message");
return 0;
}
```

### Console_bridge
If [`console_bridge`](https://github.com/ros/console_bridge) is found on the system during the
cmake run, logging commands will be done by `console_bridge`. In this case, the define `ROS_BUILD`
will be set. When built inside a catkin workspace, logging commands are automatically translated
into ROS logging commands.

If you compile this library against `console_bridge`, make sure to set the logging level in your
application, as by default `console_bridge` will only print messages of level WARNING or higher.
See [`examples/primary_pipeline.cpp`](examples/primary_pipeline.cpp) as an example.

Whenever you compile this library against `console_bridge`, make sure to set the logging level in
your application, as by default `console_bridge` will only print messages of level WARNING or
higher. See [`examples/primary_pipeline.cpp`](examples/primary_pipeline.cpp) as an example.
The ROS logger will be moved to the ROS driver in a future release.
2 changes: 1 addition & 1 deletion include/ur_client_library/comm/bin_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ class BinParser
*/
void debug()
{
LOG_DEBUG("BinParser: %p - %p (%zu bytes)", buf_pos_, buf_end_, buf_end_ - buf_pos_);
URCL_LOG_DEBUG("BinParser: %p - %p (%zu bytes)", buf_pos_, buf_end_, buf_end_ - buf_pos_);
}
};

Expand Down
24 changes: 12 additions & 12 deletions include/ur_client_library/comm/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ class Pipeline
*/
virtual ~Pipeline()
{
LOG_DEBUG("Destructing pipeline");
URCL_LOG_DEBUG("Destructing pipeline");
stop();
}

Expand Down Expand Up @@ -302,7 +302,7 @@ class Pipeline
if (!running_)
return;

LOG_DEBUG("Stopping pipeline! <%s>", name_.c_str());
URCL_LOG_DEBUG("Stopping pipeline! <%s>", name_.c_str());

running_ = false;

Expand Down Expand Up @@ -342,7 +342,7 @@ class Pipeline

void runProducer()
{
LOG_DEBUG("Starting up producer");
URCL_LOG_DEBUG("Starting up producer");
std::ifstream realtime_file("/sys/kernel/realtime", std::ios::in);
bool has_realtime;
realtime_file >> has_realtime;
Expand All @@ -363,7 +363,7 @@ class Pipeline
int ret = pthread_setschedparam(this_thread, SCHED_FIFO, &params);
if (ret != 0)
{
LOG_ERROR("Unsuccessful in setting producer thread realtime priority. Error code: %d", ret);
URCL_LOG_ERROR("Unsuccessful in setting producer thread realtime priority. Error code: %d", ret);
}
// Now verify the change in thread priority
int policy = 0;
Expand All @@ -376,24 +376,24 @@ class Pipeline
// Check the correct policy was applied
if (policy != SCHED_FIFO)
{
LOG_ERROR("Producer thread: Scheduling is NOT SCHED_FIFO!");
URCL_LOG_ERROR("Producer thread: Scheduling is NOT SCHED_FIFO!");
}
else
{
LOG_INFO("Producer thread: SCHED_FIFO OK");
URCL_LOG_INFO("Producer thread: SCHED_FIFO OK");
}

// Print thread scheduling priority
LOG_INFO("Thread priority is %d", params.sched_priority);
URCL_LOG_INFO("Thread priority is %d", params.sched_priority);
}
else
{
LOG_ERROR("Could not get maximum thread priority for producer thread");
URCL_LOG_ERROR("Could not get maximum thread priority for producer thread");
}
}
else
{
LOG_WARN("No realtime capabilities found. Consider using a realtime system for better performance");
URCL_LOG_WARN("No realtime capabilities found. Consider using a realtime system for better performance");
}
std::vector<std::unique_ptr<T>> products;
while (running_)
Expand All @@ -409,13 +409,13 @@ class Pipeline
{
if (!queue_.tryEnqueue(std::move(p)))
{
LOG_ERROR("Pipeline producer overflowed! <%s>", name_.c_str());
URCL_LOG_ERROR("Pipeline producer overflowed! <%s>", name_.c_str());
}
}

products.clear();
}
LOG_DEBUG("Pipeline producer ended! <%s>", name_.c_str());
URCL_LOG_DEBUG("Pipeline producer ended! <%s>", name_.c_str());
notifier_.stopped(name_);
}

Expand All @@ -442,7 +442,7 @@ class Pipeline
}
}
consumer_->stopConsumer();
LOG_DEBUG("Pipeline consumer ended! <%s>", name_.c_str());
URCL_LOG_DEBUG("Pipeline consumer ended! <%s>", name_.c_str());
notifier_.stopped(name_);
}
};
Expand Down
2 changes: 1 addition & 1 deletion include/ur_client_library/comm/producer.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class URProducer : public IProducer<T>
if (stream_.closed())
return false;

LOG_WARN("Failed to read from stream, reconnecting in %ld seconds...", timeout_.count());
URCL_LOG_WARN("Failed to read from stream, reconnecting in %ld seconds...", timeout_.count());
std::this_thread::sleep_for(timeout_);

if (stream_.connect())
Expand Down
10 changes: 5 additions & 5 deletions include/ur_client_library/comm/script_sender.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class ScriptSender
}
if (requestRead())
{
LOG_INFO("Robot requested program");
URCL_LOG_INFO("Robot requested program");
sendProgram();
}
server_.disconnectClient();
Expand All @@ -105,12 +105,12 @@ class ScriptSender
}
else
{
LOG_WARN("Received unexpected message on script request port ");
URCL_LOG_WARN("Received unexpected message on script request port ");
}
}
else
{
LOG_WARN("Could not read on script request port");
URCL_LOG_WARN("Could not read on script request port");
}
return false;
}
Expand All @@ -123,11 +123,11 @@ class ScriptSender

if (server_.write(data, len, written))
{
LOG_INFO("Sent program to robot");
URCL_LOG_INFO("Sent program to robot");
}
else
{
LOG_ERROR("Could not send program to robot");
URCL_LOG_ERROR("Could not send program to robot");
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion include/ur_client_library/comm/shell_consumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class ShellConsumer : public IConsumer<T>
*/
virtual bool consume(std::shared_ptr<T> product)
{
LOG_INFO("%s", product->toString().c_str());
URCL_LOG_INFO("%s", product->toString().c_str());
return true;
}

Expand Down
4 changes: 2 additions & 2 deletions include/ur_client_library/comm/stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class URStream : public TCPSocket
*/
void disconnect()
{
LOG_DEBUG("Disconnecting from %s:%d", host_.c_str(), port_);
URCL_LOG_DEBUG("Disconnecting from %s:%d", host_.c_str(), port_);
TCPSocket::close();
}

Expand Down Expand Up @@ -141,7 +141,7 @@ bool URStream<T>::read(uint8_t* buf, const size_t buf_len, size_t& total)
remainder = T::HeaderType::getPackageLength(buf);
if (remainder >= (buf_len - sizeof(typename T::HeaderType::_package_size_type)))
{
LOG_ERROR("Packet size %zd is larger than buffer %zu, discarding.", remainder, buf_len);
URCL_LOG_ERROR("Packet size %zd is larger than buffer %zu, discarding.", remainder, buf_len);
return false;
}
initial = false;
Expand Down
60 changes: 60 additions & 0 deletions include/ur_client_library/default_log_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// -- BEGIN LICENSE BLOCK ----------------------------------------------
// Copyright 2021 Universal Robots A/S
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// All source code contained in and/or linked to in this message (the “Source Code”) is subject to the copyright of
// Universal Robots A/S and/or its licensors. THE SOURCE CODE IS PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING – BUT NOT LIMITED TO – WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
// NONINFRINGEMENT. USE OF THE SOURCE CODE IS AT YOUR OWN RISK AND UNIVERSAL ROBOTS A/S AND ITS LICENSORS SHALL, TO THE
// MAXIMUM EXTENT PERMITTED BY LAW, NOT BE LIABLE FOR ANY ERRORS OR MALICIOUS CODE IN THE SOURCE CODE, ANY THIRD-PARTY
// CLAIMS, OR ANY OTHER CLAIMS AND DAMAGES, INCLUDING INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR PUNITIVE DAMAGES,
// OR ANY LOSS OF PROFITS, EXPECTED SAVINGS, OR REVENUES, WHETHER INCURRED DIRECTLY OR INDIRECTLY, OR ANY LOSS OF DATA,
// USE, GOODWILL, OR OTHER INTANGIBLE LOSSES, RESULTING FROM YOUR USE OF THE SOURCE CODE. You may make copies of the
// Source Code for use in connection with a Universal Robots or UR+ product, provided that you include (i) an
// appropriate copyright notice (“© [the year in which you received the Source Code or the Source Code was first
// published, e.g. “2021”] Universal Robots A/S and/or its licensors”) along with the capitalized section of this notice
// in all copies of the Source Code. By using the Source Code, you agree to the above terms. For more information,
// please contact legal@universal-robots.com.
// -- END LICENSE BLOCK ------------------------------------------------

#pragma once

#include "ur_client_library/log.h"

namespace urcl
{
/*!
* \brief LogHandler object for default handling of logging messages.
* This class is used when no other LogHandler is registered
*/
class DefaultLogHandler : public LogHandler
{
public:
/*!
* \brief Construct a new DefaultLogHandler object
*/
DefaultLogHandler();

/*!
* \brief Function to log a message
*
* \param file The log message comes from this file
* \param line The log message comes from this line
* \param loglevel Indicates the severity of the log message
* \param log Log message
*/
void log(const char* file, int line, LogLevel loglevel, const char* log) override;
};

} // namespace urcl
Loading