Coder Social home page Coder Social logo

rust-syslog's Introduction

Sending to Syslog in Rust

Build Status Coverage Status

A small library to write to local syslog.

Installation

syslog is available on crates.io and can be included in your Cargo enabled project like this:

[dependencies]
syslog = "^6.0"

documentation

Reference documentation is available here.

Example

extern crate syslog;

use syslog::{Facility, Formatter3164};

fn main() {
  let formatter = Formatter3164 {
    facility: Facility::LOG_USER,
    hostname: None,
    process: "myprogram".into(),
    pid: 42,
  };

  match syslog::unix(formatter) {
    Err(e)         => println!("impossible to connect to syslog: {:?}", e),
    Ok(mut writer) => {
      writer.err("hello world").expect("could not write error message");
    }
  }
}

The struct syslog::Logger implements Log from the log crate, so it can be used as backend for other logging systems:

extern crate syslog;
#[macro_use]
extern crate log;

use syslog::{Facility, Formatter3164, BasicLogger};
use log::{SetLoggerError, LevelFilter};

fn main() {
    let formatter = Formatter3164 {
        facility: Facility::LOG_USER,
        hostname: None,
        process: "myprogram".into(),
        pid: 0,
    };

    let logger = syslog::unix(formatter).expect("could not connect to syslog");
    log::set_boxed_logger(Box::new(BasicLogger::new(logger)))
            .map(|()| log::set_max_level(LevelFilter::Info));

    info!("hello world");
}

There are 3 functions to create loggers:

  • the unix function sends to the local syslog through a Unix socket: syslog::unix(formatter)
  • the tcp function takes an address for a remote TCP syslog server: tcp(formatter, "127.0.0.1:4242")
  • the udp function takes an address for a local port, and the address remote UDP syslog server: udp(formatter, "127.0.0.1:1234", "127.0.0.1:4242")

rust-syslog's People

Contributors

arfey avatar argv-minus-one avatar bkchr avatar cameronism avatar ctrlaltf24 avatar edneville avatar geal avatar gkurz avatar inejge avatar jszwedko avatar kixunil avatar lucab avatar lukesteensen avatar mikevinmike avatar mkocot avatar oherrala avatar polachok avatar robertof avatar ryandbair avatar simias avatar tailhook avatar urandom2 avatar vorner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

rust-syslog's Issues

Wrong process name/pid

In OS X the logs look like this

Aug  4 16:57:15 Seppos-MacBook-Air Unknown[4294967295] <Alert>: "hello world"

Notice Unknown[4294967295], which are supposed to be the process name and id, both are incorrect.

In Linux, they look like this

Aug  4 23:59:14 vagrant-ubuntu-trusty-64 ntpdate[1436]: adjust time server 91.189.89.199 offset -0.007467 sec
Aug  4 23:59:51 vagrant-ubuntu-trusty-64  "hello world"

Included ntpdate as a reference. Process name and pid are skipped.

issues on sending logs to tcp

  1. can't integrate with the log crate when using tcp (unix is ok).

I debugged this by starting rsyslog with rsyslogd -dn, the output shows imtcp accepted the connection, but no log entry is added. I suspect that logs are not sent when using info! from log crate.

  1. when using logger.info(...), must manually add '\n' at the end of every message.
  2. time is not local

Please consider make crate description more informative

Currently the description for this crate reads (in full):

Send log messages to syslog

How about updating it to something along the lines of:

Pure Rust implementation for sending log messages to syslog on platforms supporting ipc, tcp or udp sockets

?

That way how the crate actually works would become more obvious for users of the crate.

At least my expectation was that a crate under this name would work on any system providing the relevant Posix API, not relying on specific implementation details.

can you help me get this to work on ESP32?

I've tried using your crate to log to a remote syslog server from my ESP32, but with version >=6.0.0 compilation fails like that:

error[E0425]: cannot find value `_SC_HOST_NAME_MAX` in crate `libc`
  --> /home/user/.cargo/registry/src/github.com-1...3/hostname-0.3.1/src/nix.rs:17:38
   |
17 |         unsafe { libc::sysconf(libc::_SC_HOST_NAME_MAX) as libc::size_t };
   |                                      ^^^^^^^^^^^^^^^^^ not found in `libc`

and with version <= 5.0.0 like that:

error[E0609]: no field `tm_gmtoff` on type `tm`
   --> /home/user/.cargo/registry/src/github.com-1...3/time-0.1.45/src/sys.rs:392:30
    |
392 |             let gmtoff = out.tm_gmtoff;
    |                              ^^^^^^^^^ unknown field

stream logs never get flushed

Since #30, TcpStream and UdpStream use a BufWriter, which gets flushed in the flush() method in the Log trait impl. However, this method never actually is called in the normal use of the log crate (e.g., log!() and friends never call it). This means a program which logs less than one BufWriter worth of data (8KB) will never actually emit any of those messages, and the last few messages logged are always lost.

This can be easily demonstrated with the following program, which (if run on a system where /dev/log is a stream-mode domain socket) will never log anything:

fn main() {
    syslog::init_unix(syslog::Facility::LOG_USER, log::LevelFilter::Info);
    log::info!("test");
}

Explicitly calling flush does, of course, work:

fn main() {
    syslog::init_unix(syslog::Facility::LOG_USER, log::LevelFilter::Info);
    log::info!("test");
    log::logger().flush();
}

The following patch fixes this, at the cost of doing rather a lot more system calls under load:

diff --git a/src/lib.rs b/src/lib.rs
index 2971142..cb04df3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -175,6 +175,7 @@ impl Write for LoggerBackend {
                 socket
                     .write(&message[..])
                     .and_then(|sz| socket.write(&null).map(|_| sz))
+                    .and_then(|sz| socket.flush().map(|_| sz))
             }
             LoggerBackend::Udp(ref socket, ref addr) => socket.send_to(&message[..], addr),
             LoggerBackend::Tcp(ref mut socket) => socket.write(&message[..]),
@@ -198,6 +199,7 @@ impl Write for LoggerBackend {
                 socket
                     .write_fmt(args)
                     .and_then(|_| socket.write(&null).map(|_| ()))
+                    .and_then(|sz| socket.flush().map(|_| sz))
             }
             LoggerBackend::Udp(ref socket, ref addr) => {
                 let message = fmt::format(args);

Normally I run syslog in datagram mode, so I've never run into this before.

Proposal: allow compilation on systems without UNIX sockets

Right now the module includes std::os::unix::net to support UNIX sockets, however this core module is not built at all on non-UNIX platforms (e.g. Windows). The module should still be able to function though, with the TCP and UDP backends.

One idea to add #[cfg(unix)] before std::os::unix::net, add a new error kind "UnsupportedPlatform" and return that error when functions such as unix are called from within unsupported platforms.

I have implemented something like that here: Robertof@bffd3a3

If this looks good to you, I can make a PR.

Thanks,
Roberto

Make LogFormat trait public?

Right now, the public interface of Logger takes in messages of a type variable T. There's no other reference in the documentation for what this type is, or what kind of things are LogFormat (I assume Formatter3164 and Formatter5424 are, but there is no hint or information from the documentation which indicates this).

Could we possibly have the LogFormat trait be public, or at least make some sub-trait of it public?

If the goal of having it private is to prevent breaking changes, then it could be changed to a pair of traits like:

// public trait, exported to crate root
pub trait LogFormat<T>: intentionally_private::LogFormat { }
mod intentionally_private {
    pub LogFormat {
        // actual methods here
    }
}
// all formatters implementing LogFormat implement both traits, so the public trait will show up in the documentation.
// anything requiring LogFormat publicly requires the outer `LogFormat`, not `intentionally_private::LogFormat`

Invalid timestamp format for RFC 5424

According to the RFC 5424 section 6 the timestamp second should have at most 6 digits after the dot (see TIME-SECFRAC):

      TIMESTAMP       = NILVALUE / FULL-DATE "T" FULL-TIME
      FULL-DATE       = DATE-FULLYEAR "-" DATE-MONTH "-" DATE-MDAY
      DATE-FULLYEAR   = 4DIGIT
      DATE-MONTH      = 2DIGIT  ; 01-12
      DATE-MDAY       = 2DIGIT  ; 01-28, 01-29, 01-30, 01-31 based on
                                ; month/year
      FULL-TIME       = PARTIAL-TIME TIME-OFFSET
      PARTIAL-TIME    = TIME-HOUR ":" TIME-MINUTE ":" TIME-SECOND
                        [TIME-SECFRAC]
      TIME-HOUR       = 2DIGIT  ; 00-23
      TIME-MINUTE     = 2DIGIT  ; 00-59
      TIME-SECOND     = 2DIGIT  ; 00-59
      TIME-SECFRAC    = "." 1*6DIGIT
      TIME-OFFSET     = "Z" / TIME-NUMOFFSET
      TIME-NUMOFFSET  = ("+" / "-") TIME-HOUR ":" TIME-MINUTE

Here is an example of what the library produces with RFC 5424 format:

2023-05-15T14:38:30.099254959Z

Moreover, citing from RFC 5424, section 6.2.3:

The TIMESTAMP field is a formalized timestamp derived from [[RFC3339](https://datatracker.ietf.org/doc/html/rfc3339)].

   Whereas [[RFC3339](https://datatracker.ietf.org/doc/html/rfc3339)] makes allowances for multiple syntaxes, this
   document imposes further restrictions.  The TIMESTAMP value MUST
   follow these restrictions:

[...]

   Example 5 - An Invalid TIMESTAMP

         2003-08-24T05:14:15.000000003-07:00

   This example is nearly the same as Example 4, but it is specifying
   TIME-SECFRAC in nanoseconds.  This results in TIME-SECFRAC being
   longer than the allowed 6 digits, which invalidates it.

The last example, cited from the RFC explicitly states that nanosecond resolution is not allowed according to the specification.

Make formatter5424 deterministic for strutured data serialization

This formatter uses a HashMap for storing the structured data attached to an event. As the default HashMap randomizes the hash, the sd parameters come out in a random order in the syslogged event. This can be annoying for an event parser, or even for the human eye.
Perhaps it would be better to sort the keys alphabetically in format_5424_structured_data ?

Formatter*::pid takes i32, but std::process::id returns u32

All,

In order to run properly, I must do the following:

    /* get our process id (syslog takes i32, but we get u32) */
    let p = process::id();
    let pid = if p > std::i32::MAX as u32 {
        0
    } else {
        p as i32
    };

    /* format for our syslog messages */
    let formatter = Formatter3164 {
        facility: Facility::LOG_USER,
        hostname: None,
        process: "myrustprocess".into(),
        pid: pid,
    };

If we could change the type of pid to be u32, then we wouldn't have to jump through the overflow check...

I've checked and both Formatter* structs are i32 for pid

Thanks!

Jason

EPROTOTYPE is not constant between platforms

In the commit 01625ab a dependency to libc crate was removed and EPROTOTYPE was hard coded as constant with value 91. However, this is not portable between platforms.

Quick grep over libc crate's source code reveals that EPROTOTYPE can be (this is not definitive list):

  • 98 in Linux running on MIPS (both 32bit and 64bit)
  • 41 in Linux running on SPARK (both 32bit and 64bit)
  • 41 is also used in Apple, and FreeBSD, NetBSD and OpenBSD
  • 98 in Solaris

Update log to 0.4

Version 0.4.x of log is available. Please update and fix the compilation issues.

Make possible to customize filtering of messages according to crates

There are no clear criteria for separating messages according to the log level.
So some crates log every byte in info level, while other more conveniently move such info to trace level.
As example, in my project I have such config for env_logger:

debug,tokio=warn,request=warn,hyper=warn,
serde_xml_rs=warn,reqwest=warn,trust_dns_proto=warn,
trust_dns_resolver=warn,couchbase=warn 

So it would be nice if it is possible at least filter messages before send them to syslog via crate names.

One of possible variants of solution would be generalize solution from android_logger: https://docs.rs/android_logger/0.11.1/android_logger/struct.FilterBuilder.html

It make possible to construct via builder pattern, plus you can construct filter from RUST_LOG via let filter = android_logger::FilterBuilder::from_env("RUST_LOG").build();

Standard init for `log` crate

It seems this crate have Log implemented but does no init() method. Is this intentional? Should I use log::set_logger with a lambda directly? (The log crate does not recommend this)

how could the library work in non blocking mode?

possible ideas:

  • add a set_non_blocking (or better, set_blocking) method and implement AsRawFd to get access to the file descriptor to register in in mio and others
  • add a way for LoggerBackend to hold an instance of Write, and let the calling code set up the backend

Making `err()`, `notice()` &c take a `&mut self` (on Logger) is inconvenient

Tokio tracing is a structured logging and diagnostics system that is particularly async-friendly. In particular, it makes a very clear distinction between producing events and consuming them, to the extent that the crate offers no support for consuming them (just producing). tokio-subscriber is one (popular) crate for setting up the consumer-side. It allows one to build consumers up out of "layers" each of which can handle events in different ways.

I'm attempting to use rust-syslog to write such a Layer that sends Events to syslog. My scheme was to have my Layer implementation have a Logger field. In Layer::on_event() (the method I need to implement) I would format the Event and then invoke self.logger.err(msg) (or self.logger.info(msg) &c).

Thing is, on_event() takes an immutable &self. This means that if I store an instance of your Logger in my Layer, I can't send the message off to syslog (since the Logger's methods such as err(), notice() and so forth all require a mutable reference to self).

I searched this repo's issues and TBH I'm surprised this hasn't come up before-- I, at least, was surprised that sending a message through my Logger was a mutating event. One can write to a std::fs::File without needing a &mut self, e.g. Furthermore, I would note that a lot of your backends don't strictly need a mutable reference-- most of them wind up going through a &self (datagram, UdpSocket &c)-- it's only where you use Write & friends that you need the exclusive borrow.

Not sure what I really expect, since changing the the Logger interface would be a majorly breaking change. I guess I just wanted to alert you to this.

FWIW, I tracing-subscriber offers a Layer implementation that writes to file, so I took a peek:

   // format the message into `buf`...
   // Pseudo-code
   let mut writer = &self.file;
  let _ = io::Write::write_all(&mut writer, buf.as_bytes());

The trick here is that Write is implemented for both File and &File (same for TcpStream, btw) and File's impl internally works with &self-- the &mut self is an artifact of the Write interface. So on that call to write_all() they're passing a mutable reference to an immutable reference to File to the Write impl on &File... which promptly drops the mutable borrow and proceeds happily with just a &self.

Reddit discussion here.

Some way to send borrowed strings to an Rfc3164 logger?

Right now the message type for syslog::Logger is a type parameter on the type itself. This forces me to only ever use one type of message on the logger, when it seems like it could otherwise handle multiple.

My main annoyance with this is trying to send an &str to a logger, and store that logger within a structure. The type would be something like Logger<LoggerBackend, &str, Formatter3164>, but I can't find an appropriate lifetime for &str. I need to be able to send it borrowed strings from different points in the program, and those strings have different lifetimes since I'm borrowing them from different places.

Would it be possible to refactor the Logger struct to no longer be limited to one single message type? This would clear up some other problems like wanting to send an &str in some places and std::fmt::Arguments in others.

Unix style logger (and possibly others) don't reconnect on send error

This library continues to attempt to send to a broken fd (for example if the syslogd is restarted, causing /dev/log to have a new inode), as seen in this strace snippet:

sendto(3, "<150>Jun 11 21:36:55 syslog-test"..., 47, 0, NULL, 0) = 47
nanosleep({1, 0}, 0x7ffca177d970)       = 0
sendto(3, "<150>Jun 11 21:36:56 syslog-test"..., 47, 0, NULL, 0) = 47
nanosleep({1, 0}, 0x7ffca177d970)       = 0
sendto(3, "<150>Jun 11 21:36:57 syslog-test"..., 47, 0, NULL, 0) = -1 ECONNREFUSED (Connection refused)
nanosleep({1, 0}, 0x7ffca177d970)       = 0
sendto(3, "<150>Jun 11 21:36:58 syslog-test"..., 47, 0, NULL, 0) = -1 ENOTCONN (Transport endpoint is not connected)
nanosleep({1, 0}, 0x7ffca177d970)       = 0
sendto(3, "<150>Jun 11 21:36:59 syslog-test"..., 47, 0, NULL, 0) = -1 ENOTCONN (Transport endpoint is not connected)

Whereas the libc syslog function automatically reconnects:

sendto(3, "<14>Jun 11 21:34:38 syslog-test."..., 47, MSG_NOSIGNAL, NULL, 0) = 47
select(0, NULL, NULL, NULL, {1, 0})     = 0 (Timeout)
sendto(3, "<14>Jun 11 21:34:39 syslog-test."..., 47, MSG_NOSIGNAL, NULL, 0) = 47
select(0, NULL, NULL, NULL, {1, 0})     = 0 (Timeout)
sendto(3, "<14>Jun 11 21:34:40 syslog-test."..., 47, MSG_NOSIGNAL, NULL, 0) = -1 ECONNREFUSED (Connection refused)
close(3)                                = 0
socket(PF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/dev/log"}, 110) = 0
sendto(3, "<14>Jun 11 21:34:40 syslog-test."..., 47, MSG_NOSIGNAL, NULL, 0) = 47
select(0, NULL, NULL, NULL, {1, 0})     = 0 (Timeout)
sendto(3, "<14>Jun 11 21:34:41 syslog-test."..., 47, MSG_NOSIGNAL, NULL, 0) = 47

How to set the log to respect log-specification?

Great lib, thanks.

I have a problem when using the lib:
It can only set log-level and does not follow log-specification.

For example:
I want to show my_app's all debug log, but all others are in info-level:

RUST_LOG=info;my_app=debug

Is there a way to implement this? Thanks very much!

syslog is not prepared to deal with ENOBUFS

On NetBSD, you can get ENOBUFS if you write "too quickly" to /dev/log (unix domain socket). However, the rust syslog code has no provision for handling that error or for that matter, the need to re-connect (as already noted in issue #21). Looking at the NetBSD syslog(3) implementation, I find code which looks like this (in C, of course):

        /*
         * If the send() failed, there are two likely scenarios:
         *  1) syslogd was restarted
         *  2) /dev/log is out of socket buffer space
         * We attempt to reconnect to /dev/log to take care of
         * case #1 and keep send()ing data to cover case #2
         * to give syslogd a chance to empty its socket buffer.
         */
        for (tries = 0; tries < MAXTRIES; tries++) {
                if (send(data->log_file, tbuf, cnt, 0) != -1)
                        break;
                if (errno != ENOBUFS) {
                        disconnectlog_r(data);
                        connectlog_r(data);
                } else
                        (void)usleep(1);
        }

But there is no corresponding code in this implementation. This causes the ENOBUFS error to be "passed upwards" to the user, which in my case is routinator from NLnetLabs (available at https://github.com/NLnetLabs/routinator), and ... I have experienced that this software will exit "mysteriously" with "Logging to syslog failed: Format. Exiting." printed to stderr, due to the missing handling of ENOBUFS (I have the syscall trace to prove that). Let me suggest that some improvement of the robustness along the lines above would be beneficial. My ability to suggest how this should be done in rust is sadly not there...

UDP syslog example

I am currently trying to use the syslog crate to send messages to a remote syslog server over UDP.

My current instantiation is: syslog::udp(Formatter3164::default(), UnixStream::connect("/dev/log")?, (syslog_ip,514 as u16)); but this is failing because apparently local and server need to be the same type?

Is there any example code that could be provided on how one uses this to connect to a remote syslog server?

Formatter5424 is not compliant with the RFC

When using Formatter5424, a redundant space is added between PRI and VERSION fields.
<134> 1 2021-12-08T10:54:02Z localhost [...]
instead of
<134>1 2021-12-08T10:54:02Z localhost [...]

This makes this formatter unusable with rsyslog's default parser for example.

Attached patch

--- /nfs/thirdparty/rust-vendor/syslog/src/format.rs	2021-12-08 13:58:10.606694317 +0100
+++ syslog/src/format.rs	2021-12-08 12:00:44.361712761 +0100
@@ -114,7 +114,7 @@
   fn format<W: Write>(&self, w: &mut W, severity: Severity, log_message: (i32, StructuredData, T))   -> Result<()> {
     let (message_id, data, message) = log_message;
 
-    write!(w, "<{}> {} {} {} {} {} {} {} {}",
+    write!(w, "<{}>{} {} {} {} {} {} {} {}",
       encode_priority(severity, self.facility),
       1, // version
       time::now_utc().rfc3339(),

Potential improvements for slog.

Hi,

I'm working on slog - structured logging for rust and I'm using this crate have some feature request that would make code in slog-syslog easier.

First, is Box in Box<Logger> really necessary? I wish syslog::Logger was a trait, or was struct Logger<W : std::io::Write> so I can make it to write to Vec<u8>, TcpSstream or just anything implementing std::io::Write.

Second, I wish instead of 3 methods for different formats, there was just Format trait, that serializes stuff writing it to W : io::Write. This way Logger could be struct Logger<W : std::io::Write, F : Format> which would be extensible, easier to use and future-proof.

Anyway, thanks for your crate, initial implementation in slog seems to work. Please let me know what you think.

Relicense under dual MIT/Apache-2.0

This issue was automatically generated. Feel free to close without ceremony if
you do not agree with re-licensing or if it is not possible for other reasons.
Respond to @cmr with any questions or concerns, or pop over to
#rust-offtopic on IRC to discuss.

You're receiving this because someone (perhaps the project maintainer)
published a crates.io package with the license as "MIT" xor "Apache-2.0" and
the repository field pointing here.

TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that
license is good for interoperation. The MIT license as an add-on can be nice
for GPLv2 projects to use your code.

Why?

The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.

Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it
.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.

How?

To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright, due to not being a "creative
work", e.g. a typo fix) and then add the following to your README:

## License

Licensed under either of

 * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.

and in your license headers, if you have them, use the following boilerplate
(based on that used in Rust):

// Copyright 2016 rust-syslog Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

It's commonly asked whether license headers are required. I'm not comfortable
making an official recommendation either way, but the Apache license
recommends it in their appendix on how to use the license.

Be sure to add the relevant LICENSE-{MIT,APACHE} files. You can copy these
from the Rust repo for a plain-text
version.

And don't forget to update the license metadata in your Cargo.toml to:

license = "MIT OR Apache-2.0"

I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!

Contributor checkoff

To agree to relicensing, comment with :

I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.

Or, if you're a contributor, you can check the box in this repo next to your
name. My scripts will pick this exact phrase up and check your checkbox, but
I'll come through and manually review this issue later as well.

Extra quotes around log message

Running the example from the README I'm getting the following line in the log

Aug  4 16:57:15 Seppos-MacBook-Air Unknown[4294967295] <Alert>: "hello world"

However the quotes around "hello world" should not be there, other software's messages in syslog does not include quotes around their content.

Appending null byte in the write impl has unintended consequences

As promised, I went to confirm the changes work and I discovered some unintended behaviour of the null byte fix.

socket.write(&message[..]).and_then(|_| socket.write(&null))

On success, this'll always return Ok(1). This leads to the caller (eg. write_all, or someone else trying really hard to submit the whole message) retrying to send the same message with the first byte removed, the next time with another one removed, etc. This leads to the same message being submitted again and again (in more and more truncated way):

Aug 18 20:21:17 hydra 0:21:17 pakon-aggregator[30302]: Shutting down, app: aggregator/0.1.0
Aug 18 20:21:17 hydra :21:17 pakon-aggregator[30302]: Shutting down, app: aggregator/0.1.0
Aug 18 20:21:17 hydra 21:17 pakon-aggregator[30302]: Shutting down, app: aggregator/0.1.0
Aug 18 20:21:17 hydra 1:17 pakon-aggregator[30302]: Shutting down, app: aggregator/0.1.0
Aug 18 20:21:17 hydra :17 pakon-aggregator[30302]: Shutting down, app: aggregator/0.1.0
Aug 18 20:21:17 hydra 17 pakon-aggregator[30302]: Shutting down, app: aggregator/0.1.0
Aug 18 20:21:17 hydra 7 pakon-aggregator[30302]: Shutting down, app: aggregator/0.1.0

I'm not completely sure on how to solve this properly. A workaround would be to have this:

socket.write(&message[..]).and_then(|len| socket.write(&null).map(|_| len))

But that assumes the null byte did fit when the message fit. I guess the chance of that one not fitting is pretty low and in the worst case, two messages may get concatenated, but a less hacky solution would be nice.

Make errors Send + Sync

I'm unable to return errors from my syslog thread (not using the log framework) because the errors don't implement Sync:

                match syslog.info(alert_message)
                {
                    Ok(_) => Ok(()),
                    Err(e) => Err(Box::new(e)),
                }
error[E0277]: `(dyn StdError + std::marker::Send + 'static)` cannot be shared between threads safely
   --> src/alerts/common.rs:185:35
    |
185 |                     Err(e) => Err(Box::new(e)),
    |                               --- ^^^^^^^^^^^ `(dyn StdError + std::marker::Send + 'static)` cannot be shared between threads safely
    |                               |
    |                               required by a bound introduced by this call
    |
    = help: the trait `Sync` is not implemented for `(dyn StdError + std::marker::Send + 'static)`
    = note: required because of the requirements on the impl of `Sync` for `Unique<(dyn StdError + std::marker::Send + 'static)>`
    = note: required because it appears within the type `Box<(dyn StdError + std::marker::Send + 'static)>`
    = note: required because it appears within the type `std::option::Option<Box<(dyn StdError + std::marker::Send + 'static)>>`
    = note: required because it appears within the type `error_chain::State`
    = note: required because it appears within the type `syslog::Error`
    = note: required for the cast to the object type `dyn StdError + Sync + std::marker::Send`

Could the Sync trait be added?

Is there a way to use this crate from log4rs?

Is there a way to use this crate from log4rs?

Someone implemented syslog network functionality for log4rs 8 years ago, but it didn't get merged seemingly because this crate here exists.

And there is log4rs-syslog, but that's not a full implementation, just a thin wrapper around libc's syslog() function.

Is the syslog network functionality from this crate exposed in a way that can be used from log4rs?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.