How to redirect logs to tracing?

Hello!
I'm using Rust's library - tracing for logging and 3th party library (code in C lang).

How to redirect logs from C-lang library to tracing?
I would like a homogeneous SysLog.

C macro:

#define LOG_info(f, ...)            if (LOG_LEVEL_INFO & _dbgFlag) printf("INFO[%s:%d] " f, __func__, __LINE__, ##__VA_ARGS__)

SysLog:

Jan 26 22:14:39.823 INFO my_app: fooo    //OK
Jan 26 22:14:39.823 DEBUG my_app: bar   //OK
INFO[SomeFile:123] message from external lib       //How to redirect this? 

I haven'ty done much with tracing yet, but I think I saw there was an (add on) tracing-log crate, that might connect the two?

tracing-log converts the inputs to the tracing crate into the inputs of the log crate and vice versa. It does nothing with regards to reading files written by some arbitrary C code.

1 Like

Thanks, I totally missed that the OP was using printf not some rust export method for logging via log. Anyway, this might still be the best route for the OP to unify their logging?

What they're doing has nothing to do with the log crate, so tracing-log is entirely irrelevant.

I may be wrong about this because I'm not an expert on tracing, but it seems to me they have to redirect the output of the C printf into something they can read and send to their tracing collector. Ideally, rewrite the C code to invoke a rust function calling into the tracing crate. Less ideally, spawn a thread or processes that reads from the printf output file and invokes the trace function on any input it receives. I don't think there's an easy way to merge these, because the C code isn't doing "tracing" (or "logging") as defined by the tracing crate, it's just writing text to a file.

The course of action to take also depends on what they're hoping to achieve by redirecting the output: it is just a matter of getting all of the info in the same output files, or is it a matter of treating the C library output as a configurable part of the tracing pipeline?

"irrelevant"

Rough day? Yeah, maybe you are right, I mean tracing does also have its own API for logging.

Stepping outside the box at this point, but you might be able to unify the format on stdout, by configuring tracing to use the same format (which implies abandoning timestamps), then they should just interleave on stdout. Or maybe tracing is going to stderr, often a better descriptor for log output—in which case you'll want to arrange the same on the C side. As long as the line writes are single write calls underneath, it should interleave properly. Then using something external, like for example systemd, e.g. if you are writing a daemon (service) for linux, if you want timestamps.

Or, has anyone already written some C-API to rust log crate output methods? I think that is more likely than for tracing, and thus not entirely irrelevant.

Here's the crux of the issue.

The C programming language does not have a standard feature to change where printf writes to. For most implementations, printf writes to the process' standard output stream, wherever that is, and that's that.

Some libc implementations do expose implementation-specific functions to configure printf behaviours. Rust could call those, if you know which libc you're linking against and if you can either get or write bindings for the implementation-specific functions you need. GNU libc, for example, provides this facility.

However, writing an implementation to capture printf for each libc you care to support is tedious and fragile, and you will forever be plagued with users who are using a libc you didn't account for. There are also some libc implementations you won't be able to support this way.

You'd be better off doing one of a few alternatives. Assuming this is a program running on a unix-like OS:

  • You can reopen file descriptor 1 to write to a file you control, or to a program via a pipe, and intercept all output that way - including printf output.
  • You can invoke the program using a helper program such as logger(1), or via a daemon framework such as systemd, which logs the program's stdout for you.
  • You can replace the call to printf with a function you control, allowing you to do whatever you like with the arguments.

Redirecting stdout (and, if you like, stderr) is less intrusive. Replacing printf calls is more work, but also more flexible. What the right choice is is up to you and to your design constraints.

I miss the printf too, maybe LOG_info(f, ...) obviously uses printf but it's far from obvious to me :stuck_out_tongue:

My out of the box solution, to be taken with a hefty dose of salt, is to redefine the C macro and make it call tracing somehow through FFI. Maybe that's horrendously unsafe or difficult, no idea!

1 Like

Thank you for answering my question.
I will modify the macro in C to make the output look like the tracing library.

I have one more problem with tracing library.... how to edit timestamp format? I want to add a year to timestamp.

 Jan 28 12:03:04.03 => 2021 Jan 28 12:03:04.03

Is there a C (or libc) forum you could ask about that? Or...

man 3 strftime

No. tracing library.

1 Like

Wow, sorry about that, I think I need reading glasses. :frowning:

How about this:
https://docs.rs/tracing-subscriber/0.2.15/tracing_subscriber/fmt/struct.SubscriberBuilder.html#method.with_timer

What do you mean?
It's timer... no format.

Perhaps my prior poor suggestions have conditioned you to assume this one was also poor? :wink:

The timer variable name (above linked rustdoc) was an unfortunate choice IMO, but if you click through its link you find a trait: tracing_subscriber::fmt::time::FormatTime, which has Chrono implementations, with full format string configuration. Maybe take it up with the tracing authors if that isn't enough of a pointer?

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.