Skip to content

Commit 487f92f

Browse files
author
Felix Exner
authored
Merge pull request #40 from urmahp/logging_feature
Added LogHandler, this enables the possibility to change the behavior when logging messages with this library.
2 parents 94db721 + 77f0eac commit 487f92f

21 files changed

+495
-95
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ add_library(urcl SHARED
3939
src/ur/dashboard_client.cpp
4040
src/ur/tool_communication.cpp
4141
src/rtde/rtde_writer.cpp
42+
src/default_log_handler.cpp
43+
src/log.cpp
4244
)
4345
add_library(ur_client_library::urcl ALIAS urcl)
4446
target_compile_options(urcl PRIVATE -Wall -Wextra -Wno-unused-parameter)

README.md

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ robotic manipulators.
3535
[boost](https://github.com/UniversalRobots/Universal_Robots_Client_Library/tree/boost) branch
3636
instead that requires the boost library.
3737
For the C++17 features, please use those minimum compiler versions:
38-
38+
3939
| Compiler | min. version |
4040
|-----------|--------------|
4141
| **GCC** | 7 |
4242
| **Clang** | 7 |
43-
43+
4444

4545
## Build instructions
4646
### Plain cmake
@@ -301,11 +301,87 @@ As this library was originally designed to be included into a ROS driver but als
301301
standalone library, it uses custom logging macros instead of direct `printf` or `std::cout`
302302
statements.
303303
304-
These logging macros will either be translated into `printf` statements or logging commands of
305-
[`console_bridge`](https://github.com/ros/console_bridge) if `console_bridge` is found on the system
306-
during the cmake run. In this case, the define `ROS_BUILD` will be set. When built inside a catkin
307-
workspace, logging commands are automatically translated into ROS logging commands.
304+
The macro based interface is by default using the [`DefaultLogHandler`](include/ur_client_library/default_log_handler.h)
305+
to print the logging messages as `printf` statements. It is possible to define your own log handler
306+
to change the behavior, [see create new log handler](#Create-new-log-handler) on how to.
307+
308+
### Change logging level
309+
Make sure to set the logging level in your application, as by default only messages of level
310+
WARNING or higher will be printed. See below for an example:
311+
```c++
312+
#include "ur_client_library/log.h"
313+
314+
int main(int argc, char* argv[])
315+
{
316+
urcl::setLogLevel(urcl::LogLevel::DEBUG);
317+
318+
URCL_LOG_DEBUG("Logging debug message");
319+
return 0;
320+
}
321+
```
322+
323+
### Create new log handler
324+
The logger comes with an interface [`LogHandler`](include/ur_client_library/log.h), which can be
325+
used to implement your own log handler for messages logged with this library. This can be done by
326+
inheriting from the `LogHandler class`.
327+
328+
If you want to create a new log handler in your application, you can use below example as
329+
inspiration:
330+
331+
```c++
332+
#include "ur_client_library/log.h"
333+
#include <iostream>
334+
335+
class MyLogHandler : public urcl::LogHandler
336+
{
337+
public:
338+
MyLogHandler() = default;
339+
340+
void log(const char* file, int line, urcl::LogLevel loglevel, const char* log) override
341+
{
342+
switch (loglevel)
343+
{
344+
case urcl::LogLevel::INFO:
345+
std::cout << "INFO " << file << " " << line << ": " << log << std::endl;
346+
break;
347+
case urcl::LogLevel::DEBUG:
348+
std::cout << "DEBUG " << file << " " << line << ": " << log << std::endl;
349+
break;
350+
case urcl::LogLevel::WARN:
351+
std::cout << "WARN " << file << " " << line << ": " << log << std::endl;
352+
break;
353+
case urcl::LogLevel::ERROR:
354+
std::cout << "ERROR " << file << " " << line << ": " << log << std::endl;
355+
break;
356+
case urcl::LogLevel::FATAL:
357+
std::cout << "ERROR " << file << " " << line << ": " << log << std::endl;
358+
break;
359+
default:
360+
break;
361+
}
362+
}
363+
};
364+
365+
int main(int argc, char* argv[])
366+
{
367+
urcl::setLogLevel(urcl::LogLevel::DEBUG);
368+
std::unique_ptr<MyLogHandler> log_handler(new MyLogHandler);
369+
urcl::registerLogHandler(std::move(log_handler));
370+
371+
URCL_LOG_DEBUG("logging debug message");
372+
URCL_LOG_INFO("logging info message");
373+
return 0;
374+
}
375+
```
376+
377+
### Console_bridge
378+
If [`console_bridge`](https://github.com/ros/console_bridge) is found on the system during the
379+
cmake run, logging commands will be done by `console_bridge`. In this case, the define `ROS_BUILD`
380+
will be set. When built inside a catkin workspace, logging commands are automatically translated
381+
into ROS logging commands.
382+
383+
If you compile this library against `console_bridge`, make sure to set the logging level in your
384+
application, as by default `console_bridge` will only print messages of level WARNING or higher.
385+
See [`examples/primary_pipeline.cpp`](examples/primary_pipeline.cpp) as an example.
308386
309-
Whenever you compile this library against `console_bridge`, make sure to set the logging level in
310-
your application, as by default `console_bridge` will only print messages of level WARNING or
311-
higher. See [`examples/primary_pipeline.cpp`](examples/primary_pipeline.cpp) as an example.
387+
The ROS logger will be moved to the ROS driver in a future release.

include/ur_client_library/comm/bin_parser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ class BinParser
368368
*/
369369
void debug()
370370
{
371-
LOG_DEBUG("BinParser: %p - %p (%zu bytes)", buf_pos_, buf_end_, buf_end_ - buf_pos_);
371+
URCL_LOG_DEBUG("BinParser: %p - %p (%zu bytes)", buf_pos_, buf_end_, buf_end_ - buf_pos_);
372372
}
373373
};
374374

include/ur_client_library/comm/pipeline.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ class Pipeline
267267
*/
268268
virtual ~Pipeline()
269269
{
270-
LOG_DEBUG("Destructing pipeline");
270+
URCL_LOG_DEBUG("Destructing pipeline");
271271
stop();
272272
}
273273

@@ -302,7 +302,7 @@ class Pipeline
302302
if (!running_)
303303
return;
304304

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

307307
running_ = false;
308308

@@ -342,7 +342,7 @@ class Pipeline
342342

343343
void runProducer()
344344
{
345-
LOG_DEBUG("Starting up producer");
345+
URCL_LOG_DEBUG("Starting up producer");
346346
std::ifstream realtime_file("/sys/kernel/realtime", std::ios::in);
347347
bool has_realtime;
348348
realtime_file >> has_realtime;
@@ -363,7 +363,7 @@ class Pipeline
363363
int ret = pthread_setschedparam(this_thread, SCHED_FIFO, &params);
364364
if (ret != 0)
365365
{
366-
LOG_ERROR("Unsuccessful in setting producer thread realtime priority. Error code: %d", ret);
366+
URCL_LOG_ERROR("Unsuccessful in setting producer thread realtime priority. Error code: %d", ret);
367367
}
368368
// Now verify the change in thread priority
369369
int policy = 0;
@@ -376,24 +376,24 @@ class Pipeline
376376
// Check the correct policy was applied
377377
if (policy != SCHED_FIFO)
378378
{
379-
LOG_ERROR("Producer thread: Scheduling is NOT SCHED_FIFO!");
379+
URCL_LOG_ERROR("Producer thread: Scheduling is NOT SCHED_FIFO!");
380380
}
381381
else
382382
{
383-
LOG_INFO("Producer thread: SCHED_FIFO OK");
383+
URCL_LOG_INFO("Producer thread: SCHED_FIFO OK");
384384
}
385385

386386
// Print thread scheduling priority
387-
LOG_INFO("Thread priority is %d", params.sched_priority);
387+
URCL_LOG_INFO("Thread priority is %d", params.sched_priority);
388388
}
389389
else
390390
{
391-
LOG_ERROR("Could not get maximum thread priority for producer thread");
391+
URCL_LOG_ERROR("Could not get maximum thread priority for producer thread");
392392
}
393393
}
394394
else
395395
{
396-
LOG_WARN("No realtime capabilities found. Consider using a realtime system for better performance");
396+
URCL_LOG_WARN("No realtime capabilities found. Consider using a realtime system for better performance");
397397
}
398398
std::vector<std::unique_ptr<T>> products;
399399
while (running_)
@@ -409,13 +409,13 @@ class Pipeline
409409
{
410410
if (!queue_.tryEnqueue(std::move(p)))
411411
{
412-
LOG_ERROR("Pipeline producer overflowed! <%s>", name_.c_str());
412+
URCL_LOG_ERROR("Pipeline producer overflowed! <%s>", name_.c_str());
413413
}
414414
}
415415

416416
products.clear();
417417
}
418-
LOG_DEBUG("Pipeline producer ended! <%s>", name_.c_str());
418+
URCL_LOG_DEBUG("Pipeline producer ended! <%s>", name_.c_str());
419419
notifier_.stopped(name_);
420420
}
421421

@@ -442,7 +442,7 @@ class Pipeline
442442
}
443443
}
444444
consumer_->stopConsumer();
445-
LOG_DEBUG("Pipeline consumer ended! <%s>", name_.c_str());
445+
URCL_LOG_DEBUG("Pipeline consumer ended! <%s>", name_.c_str());
446446
notifier_.stopped(name_);
447447
}
448448
};

include/ur_client_library/comm/producer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class URProducer : public IProducer<T>
122122
if (stream_.closed())
123123
return false;
124124

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

128128
if (stream_.connect())

include/ur_client_library/comm/script_sender.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class ScriptSender
8383
}
8484
if (requestRead())
8585
{
86-
LOG_INFO("Robot requested program");
86+
URCL_LOG_INFO("Robot requested program");
8787
sendProgram();
8888
}
8989
server_.disconnectClient();
@@ -105,12 +105,12 @@ class ScriptSender
105105
}
106106
else
107107
{
108-
LOG_WARN("Received unexpected message on script request port ");
108+
URCL_LOG_WARN("Received unexpected message on script request port ");
109109
}
110110
}
111111
else
112112
{
113-
LOG_WARN("Could not read on script request port");
113+
URCL_LOG_WARN("Could not read on script request port");
114114
}
115115
return false;
116116
}
@@ -123,11 +123,11 @@ class ScriptSender
123123

124124
if (server_.write(data, len, written))
125125
{
126-
LOG_INFO("Sent program to robot");
126+
URCL_LOG_INFO("Sent program to robot");
127127
}
128128
else
129129
{
130-
LOG_ERROR("Could not send program to robot");
130+
URCL_LOG_ERROR("Could not send program to robot");
131131
}
132132
}
133133
};

include/ur_client_library/comm/shell_consumer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class ShellConsumer : public IConsumer<T>
5858
*/
5959
virtual bool consume(std::shared_ptr<T> product)
6060
{
61-
LOG_INFO("%s", product->toString().c_str());
61+
URCL_LOG_INFO("%s", product->toString().c_str());
6262
return true;
6363
}
6464

include/ur_client_library/comm/stream.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class URStream : public TCPSocket
6868
*/
6969
void disconnect()
7070
{
71-
LOG_DEBUG("Disconnecting from %s:%d", host_.c_str(), port_);
71+
URCL_LOG_DEBUG("Disconnecting from %s:%d", host_.c_str(), port_);
7272
TCPSocket::close();
7373
}
7474

@@ -141,7 +141,7 @@ bool URStream<T>::read(uint8_t* buf, const size_t buf_len, size_t& total)
141141
remainder = T::HeaderType::getPackageLength(buf);
142142
if (remainder >= (buf_len - sizeof(typename T::HeaderType::_package_size_type)))
143143
{
144-
LOG_ERROR("Packet size %zd is larger than buffer %zu, discarding.", remainder, buf_len);
144+
URCL_LOG_ERROR("Packet size %zd is larger than buffer %zu, discarding.", remainder, buf_len);
145145
return false;
146146
}
147147
initial = false;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// -- BEGIN LICENSE BLOCK ----------------------------------------------
2+
// Copyright 2021 Universal Robots A/S
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
// All source code contained in and/or linked to in this message (the “Source Code”) is subject to the copyright of
17+
// Universal Robots A/S and/or its licensors. THE SOURCE CODE IS PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EXPRESS
18+
// OR IMPLIED, INCLUDING – BUT NOT LIMITED TO – WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
19+
// NONINFRINGEMENT. USE OF THE SOURCE CODE IS AT YOUR OWN RISK AND UNIVERSAL ROBOTS A/S AND ITS LICENSORS SHALL, TO THE
20+
// MAXIMUM EXTENT PERMITTED BY LAW, NOT BE LIABLE FOR ANY ERRORS OR MALICIOUS CODE IN THE SOURCE CODE, ANY THIRD-PARTY
21+
// CLAIMS, OR ANY OTHER CLAIMS AND DAMAGES, INCLUDING INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR PUNITIVE DAMAGES,
22+
// OR ANY LOSS OF PROFITS, EXPECTED SAVINGS, OR REVENUES, WHETHER INCURRED DIRECTLY OR INDIRECTLY, OR ANY LOSS OF DATA,
23+
// USE, GOODWILL, OR OTHER INTANGIBLE LOSSES, RESULTING FROM YOUR USE OF THE SOURCE CODE. You may make copies of the
24+
// Source Code for use in connection with a Universal Robots or UR+ product, provided that you include (i) an
25+
// appropriate copyright notice (“© [the year in which you received the Source Code or the Source Code was first
26+
// published, e.g. “2021”] Universal Robots A/S and/or its licensors”) along with the capitalized section of this notice
27+
// in all copies of the Source Code. By using the Source Code, you agree to the above terms. For more information,
28+
// please contact [email protected].
29+
// -- END LICENSE BLOCK ------------------------------------------------
30+
31+
#pragma once
32+
33+
#include "ur_client_library/log.h"
34+
35+
namespace urcl
36+
{
37+
/*!
38+
* \brief LogHandler object for default handling of logging messages.
39+
* This class is used when no other LogHandler is registered
40+
*/
41+
class DefaultLogHandler : public LogHandler
42+
{
43+
public:
44+
/*!
45+
* \brief Construct a new DefaultLogHandler object
46+
*/
47+
DefaultLogHandler();
48+
49+
/*!
50+
* \brief Function to log a message
51+
*
52+
* \param file The log message comes from this file
53+
* \param line The log message comes from this line
54+
* \param loglevel Indicates the severity of the log message
55+
* \param log Log message
56+
*/
57+
void log(const char* file, int line, LogLevel loglevel, const char* log) override;
58+
};
59+
60+
} // namespace urcl

0 commit comments

Comments
 (0)