SYSLOG: Add option to buffer SYSLOG output to avoid interleaving.

This commit is contained in:
Gregory Nutt 2017-05-10 14:42:43 -06:00
parent 4f18b40429
commit 20727d17c3
18 changed files with 590 additions and 134 deletions

View File

@ -11,6 +11,12 @@ config ARCH_SYSLOG
bool
default n
# Selected if the SYSLOG device supports multi-byte write operations
config SYSLOG_WRITE
bool
default n
config RAMLOG
bool "RAM log device support"
default n
@ -76,6 +82,30 @@ config DRIVER_NOTE
to read data from the in-memory, scheduler instrumentation "note"
buffer.
config SYSLOG_BUFFER
bool "Use buffered output"
default n
depends on SYSLOG_WRITE
---help---
Enables an buffering logic that will be used to serialize debug
output from concurrent tasks. This enables allocation of one buffer
per thread, each of size CONFIG_SYSLOG_BUFSIZE.
The use of SYSLOG buffering is optional. If not enabled, however,
then the output from multiple tasks that attempt to generate SYSLOG
output may be interleaved and difficult to read.
config SYSLOG_BUFSIZE
int "Output buffer size"
default 32
range 1 65535
depends on SYSLOG_BUFFER
---help---
If CONFIG_SYSLOG_BUFFER is enabled, then CONFIG_SYSLOG_BUFSIZE
provides the size of the per-thread output buffer. Setting
CONFIG_SYSLOG_BUFSIZE to a value less than one effectly disables
output SYSLOG buffering.
config SYSLOG_INTBUFFER
bool "Use interrupt buffer"
default n
@ -108,6 +138,7 @@ choice
config SYSLOG_CHAR
bool "Log to a character device"
select SYSLOG_WRITE
---help---
Enable the generic character device for the SYSLOG. The full path to the
SYSLOG device is provided by SYSLOG_DEVPATH. A valid character device (or
@ -126,6 +157,7 @@ config SYSLOG_CONSOLE
bool "Log to /dev/console"
depends on DEV_CONSOLE
select SYSLOG_SERIAL_CONSOLE if SERIAL_CONSOLE
select SYSLOG_WRITE
---help---
Use the system console as a SYSLOG output device.
@ -140,6 +172,7 @@ endchoice
config SYSLOG_FILE
bool "Sylog file output"
default n
select SYSLOG_WRITE
---help---
Build in support to use a file to collect SYSOG output. File SYSLOG
channels differ from other SYSLOG channels in that they cannot be

View File

@ -38,7 +38,7 @@
# Include SYSLOG Infrastructure
CSRCS += vsyslog.c syslog_stream.c syslog_emergstream.c syslog_channel.c
CSRCS += syslog_putc.c syslog_force.c syslog_flush.c
CSRCS += syslog_putc.c syslog_write.c syslog_force.c syslog_flush.c
ifeq ($(CONFIG_SYSLOG_INTBUFFER),y)
CSRCS += syslog_intbuffer.c

View File

@ -129,6 +129,9 @@ SYSLOG Channels
{
/* I/O redirection methods */
#ifdef CONFIG_SYSLOG_WRITE
syslog_write_t sc_write; /* Write multiple bytes */
#endif
syslog_putc_t sc_putc; /* Normal buffered output */
syslog_putc_t sc_force; /* Low-level output for interrupt handlers */
syslog_flush_t sc_flush; /* Flush buffered output (on crash) */

View File

@ -127,6 +127,9 @@ static int ramlog_poll(FAR struct file *filep, FAR struct pollfd *fds,
#ifdef CONFIG_RAMLOG_SYSLOG
static const struct syslog_channel_s g_ramlog_syslog_channel =
{
#ifdef CONFIG_SYSLOG_WRITE
syslog_default_write,
#endif
ramlog_putc,
ramlog_putc,
ramlog_flush

View File

@ -240,19 +240,57 @@ int syslog_flush_intbuffer(FAR const struct syslog_channel_s *channel,
* Name: syslog_putc
*
* Description:
* This is the low-level system logging interface.
* This is the low-level, single character, system logging interface.
*
* Input Parameters:
* ch - The character to add to the SYSLOG (must be positive).
*
* Returned Value:
* On success, the character is echoed back to the caller. A negated
* errno value is returned on any failure.
* On success, the character is echoed back to the caller. Minus one
* is returned on any failure with the errno set correctly.
*
****************************************************************************/
int syslog_putc(int ch);
/****************************************************************************
* Name: syslog_write
*
* Description:
* This is the low-level, multiple character, system logging interface.
*
* Input Parameters:
* buffer - The buffer containing the data to be output
* buflen - The number of bytes in the buffer
*
* Returned Value:
* On success, the number of characters written is returned. A negated
* errno value is returned on any failure.
*
****************************************************************************/
ssize_t syslog_write(FAR const char *buffer, size_t buflen);
/****************************************************************************
* Name: syslog_default_write
*
* Description:
* This provides a default write method for syslog devices that do not
* support multiple byte writes This functions simply loops, outputting
* one cahracter at a time.
*
* Input Parameters:
* buffer - The buffer containing the data to be output
* buflen - The number of bytes in the buffer
*
* Returned Value:
* On success, the number of characters written is returned. A negated
* errno value is returned on any failure.
*
****************************************************************************/
ssize_t syslog_default_write(FAR const char *buffer, size_t buflen);
/****************************************************************************
* Name: syslog_force
*
@ -272,6 +310,25 @@ int syslog_putc(int ch);
int syslog_force(int ch);
/****************************************************************************
* Name: syslog_dev_write
*
* Description:
* This is the low-level, multile byte, system logging interface provided
* for the character driver interface.
*
* Input Parameters:
* buffer - The buffer containing the data to be output
* buflen - The number of bytes in the buffer
*
* Returned Value:
* On success, the character is echoed back to the caller. Minus one
* is returned on any failure with the errno set correctly.
*
****************************************************************************/
ssize_t syslog_dev_write(FAR const char *buffer, size_t buflen);
/****************************************************************************
* Name: syslog_dev_putc
*

View File

@ -79,6 +79,9 @@ static int syslog_default_flush(void);
#if defined(CONFIG_RAMLOG_SYSLOG)
const struct syslog_channel_s g_default_channel =
{
#ifdef CONFIG_SYSLOG_WRITE
syslog_default_write,
#endif
ramlog_putc,
ramlog_putc,
syslog_default_flush
@ -86,6 +89,9 @@ const struct syslog_channel_s g_default_channel =
#elif defined(HAVE_LOWPUTC)
const struct syslog_channel_s g_default_channel =
{
#ifdef CONFIG_SYSLOG_WRITE
syslog_default_write,
#endif
up_putc,
up_putc,
syslog_default_flush
@ -93,6 +99,9 @@ const struct syslog_channel_s g_default_channel =
#else
const struct syslog_channel_s g_default_channel =
{
#ifdef CONFIG_SYSLOG_WRITE
syslog_default_write,
#endif
syslog_default_putc,
syslog_default_putc,
syslog_default_flush

View File

@ -56,8 +56,8 @@
* Private Function Prototypes
****************************************************************************/
static ssize_t syslog_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen);
static ssize_t syslog_chardev_write(FAR struct file *filep,
FAR const char *buffer, size_t buflen);
/****************************************************************************
* Private Data
@ -68,7 +68,7 @@ static const struct file_operations syslog_fops =
NULL, /* open */
NULL, /* close */
NULL, /* read */
syslog_write, /* write */
syslog_chardev_write, /* write */
NULL, /* seek */
NULL /* ioctl */
#ifndef CONFIG_DISABLE_POLL
@ -84,23 +84,13 @@ static const struct file_operations syslog_fops =
****************************************************************************/
/****************************************************************************
* Name: syslog_write
* Name: syslog_chardev_write
****************************************************************************/
static ssize_t syslog_write(FAR struct file *filep, FAR const char *buffer,
size_t len)
static ssize_t syslog_chardev_write(FAR struct file *filep,
FAR const char *buffer, size_t len)
{
size_t nwritten;
int ret;
for (nwritten = 0; nwritten < len; nwritten++)
{
int ch = *buffer++;
ret = syslog_putc(ch);
UNUSED(ret);
}
return len;
return syslog_write(buffer, len);
}
/****************************************************************************

View File

@ -106,14 +106,7 @@ static ssize_t syslog_console_read(FAR struct file *filep, FAR char *buffer,
static ssize_t syslog_console_write(FAR struct file *filep,
FAR const char *buffer, size_t buflen)
{
ssize_t ret = buflen;
for (; buflen; buflen--)
{
syslog_putc(*buffer++);
}
return ret;
return syslog_write(buffer, len);
}
/****************************************************************************

View File

@ -83,6 +83,9 @@ static int syslog_console_force(int ch);
static const struct syslog_channel_s g_syslog_console_channel =
{
#ifdef CONFIG_SYSLOG_WRITE
syslog_dev_write,
#endif
syslog_dev_putc,
#ifdef HAVE_LOWPUTC
up_putc,

View File

@ -74,6 +74,9 @@ static int syslog_devchan_force(int ch);
static const struct syslog_channel_s g_syslog_dev_channel =
{
#ifdef CONFIG_SYSLOG_WRITE
syslog_dev_write,
#endif
#ifdef CONFIG_SYSLOG_CHAR_CRLF
syslog_devchan_putc,
#else

View File

@ -184,6 +184,114 @@ static inline void syslog_dev_givesem(void)
sem_post(&g_syslog_dev.sl_sem);
}
/****************************************************************************
* Name: syslog_dev_outputready
*
* Description:
* Ignore any output:
*
* (1) Before the SYSLOG device has been initialized. This could happen
* from debug output that occurs early in the boot sequence before
* syslog_dev_initialize() is called (SYSLOG_UNINITIALIZED).
* (2) While the device is being initialized. The case could happen if
* debug output is generated while syslog_dev_initialize() executes
* (SYSLOG_INITIALIZING).
* (3) While we are generating SYSLOG output. The case could happen if
* debug output is generated while syslog_dev_putc() executes
* (This case is actually handled inside of syslog_semtake()).
* (4) Any debug output generated from interrupt handlers. A disadvantage
* of using the generic character device for the SYSLOG is that it
* cannot handle debug output generated from interrupt level handlers.
* (5) Any debug output generated from the IDLE loop. The character
* driver interface is blocking and the IDLE thread is not permitted
* to block.
* (6) If an irrecoverable failure occurred during initialization. In
* this case, we won't ever bother to try again (ever).
*
* NOTE: That the third case is different. It applies only to the thread
* that currently holds the sl_sem sempaphore. Other threads should wait.
* that is why that case is handled in syslog_semtake().
*
* Input Parameters:
* ch - The character to add to the SYSLOG (must be positive).
*
* Returned Value:
* On success, the character is echoed back to the caller. A negated
* errno value is returned on any failure.
*
****************************************************************************/
static int syslog_dev_outputready(void)
{
int ret;
/* Cases (4) and (5) */
if (up_interrupt_context() || getpid() == 0)
{
return -ENOSYS;
}
/* We can save checks in the usual case: That after the SYSLOG device
* has been successfully opened.
*/
if (g_syslog_dev.sl_state != SYSLOG_OPENED)
{
/* Case (1) and (2) */
if (g_syslog_dev.sl_state == SYSLOG_UNINITIALIZED ||
g_syslog_dev.sl_state == SYSLOG_INITIALIZING)
{
return -EAGAIN; /* Can't access the SYSLOG now... maybe next time? */
}
/* Case (6) */
if (g_syslog_dev.sl_state == SYSLOG_FAILURE)
{
return -ENXIO; /* There is no SYSLOG device */
}
/* syslog_dev_initialize() is called as soon as enough of the operating
* system is in place to support the open operation... but it is
* possible that the SYSLOG device is not yet registered at that time.
* In this case, we know that the system is sufficiently initialized
* to support an attempt to re-open the SYSLOG device.
*
* NOTE that the scheduler is locked. That is because we do not have
* fully initialized semaphore capability until the SYSLOG device is
* successfully initialized
*/
sched_lock();
if (g_syslog_dev.sl_state == SYSLOG_REOPEN)
{
/* Try again to initialize the device. We may do this repeatedly
* because the log device might be something that was not ready
* the first time that syslog_dev_initializee() was called (such as a
* USB serial device that has not yet been connected or a file in
* an NFS mounted file system that has not yet been mounted).
*/
DEBUGASSERT(g_syslog_dev.sl_devpath != NULL);
ret = syslog_dev_initialize(g_syslog_dev.sl_devpath,
(int)g_syslog_dev.sl_oflags,
(int)g_syslog_dev.sl_mode);
if (ret < 0)
{
sched_unlock();
return ret;
}
}
sched_unlock();
DEBUGASSERT(g_syslog_dev.sl_state == SYSLOG_OPENED);
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -354,19 +462,167 @@ int syslog_dev_uninitialize(void)
}
#endif /* CONFIG_SYSLOG_FILE */
/****************************************************************************
* Name: syslog_dev_write
*
* Description:
* This is the low-level, multile byte, system logging interface provided
* for the character driver interface.
*
* Input Parameters:
* buffer - The buffer containing the data to be output
* buflen - The number of bytes in the buffer
*
* Returned Value:
* On success, the character is echoed back to the caller. Minus one
* is returned on any failure with the errno set correctly.
*
****************************************************************************/
ssize_t syslog_dev_write(FAR const char *buffer, size_t buflen)
{
FAR const char *endptr;
ssize_t nwritten;
size_t writelen;
int errcode;
int ret;
/* Check if the system is ready to do output operations */
ret = syslog_dev_outputready();
if (ret < 0)
{
errcode = -ret;
goto errout_with_errcode;
}
/* The syslog device is ready for writing */
ret = syslog_dev_takesem();
if (ret < 0)
{
/* We probably already hold the semaphore and were probably
* re-entered by the logic kicked off by file_write().
* We might also have been interrupted by a signal. Either
* way, we are outta here.
*/
errcode = -ret;
goto errout_with_errcode;
}
/* Loop until we have output all characters */
for (endptr = buffer; *endptr != '\n'; endptr++)
{
switch (*endptr)
{
case '\r':
{
/* Write everything up to this point, ignore the carriage
* return.
*
* - buffer points to next byte to output.
* - endptr points to the carriage return.
*/
writelen = (size_t)((uintptr_t)endptr - (uintptr_t)buffer);
if (writelen > 0)
{
nwritten = file_write(&g_syslog_dev.sl_file, buffer, writelen);
if (nwritten < 0)
{
errcode = -nwritten;
goto errout_with_sem;
}
}
/* Adjust pointers */
writelen++; /* Skip the carriage return */
buffer += writelen; /* Points past the carriage return */
}
break;
case '\n':
{
/* Write everything up to this point, then add a carriage
* return and linefeed;
*
* - buffer points to next byte to output.
* - endptr points to the new line.
*/
writelen = (size_t)((uintptr_t)endptr - (uintptr_t)buffer);
if (writelen > 0)
{
nwritten = file_write(&g_syslog_dev.sl_file, buffer, writelen);
if (nwritten < 0)
{
errcode = -nwritten;
goto errout_with_sem;
}
}
nwritten = file_write(&g_syslog_dev.sl_file, g_syscrlf, 2);
if (nwritten < 0)
{
errcode = -nwritten;
goto errout_with_sem;
}
/* Adjust pointers */
writelen++; /* Skip the line feed */
buffer += writelen; /* Points past the line feed */
}
break;
default:
break;
}
}
/* Write any data at the end of the buffer.
*
* - buffer points to next byte to output.
* - endptr points to the NULL terminator.
*/
writelen = (size_t)((uintptr_t)endptr - (uintptr_t)buffer);
if (writelen > 0)
{
nwritten = file_write(&g_syslog_dev.sl_file, buffer, writelen);
if (nwritten < 0)
{
errcode = -nwritten;
goto errout_with_sem;
}
}
syslog_dev_givesem();
return buflen;
errout_with_sem:
syslog_dev_givesem();
errout_with_errcode:
set_errno(errcode);
return -1;
}
/****************************************************************************
* Name: syslog_dev_putc
*
* Description:
* This is the low-level system logging interface provided for the
* character driver interface.
* This is the low-level, single character, system logging interface
* provided for the character driver interface.
*
* Input Parameters:
* ch - The character to add to the SYSLOG (must be positive).
*
* Returned Value:
* On success, the character is echoed back to the caller. A negated
* errno value is returned on any failure.
* On success, the character is echoed back to the caller. Minus one
* is returned on any failure with the errno set correctly.
*
****************************************************************************/
@ -377,99 +633,15 @@ int syslog_dev_putc(int ch)
int errcode;
int ret;
/* Ignore any output:
*
* (1) Before the SYSLOG device has been initialized. This could happen
* from debug output that occurs early in the boot sequence before
* syslog_dev_initialize() is called (SYSLOG_UNINITIALIZED).
* (2) While the device is being initialized. The case could happen if
* debug output is generated while syslog_dev_initialize() executes
* (SYSLOG_INITIALIZING).
* (3) While we are generating SYSLOG output. The case could happen if
* debug output is generated while syslog_dev_putc() executes
* (This case is actually handled inside of syslog_semtake()).
* (4) Any debug output generated from interrupt handlers. A disadvantage
* of using the generic character device for the SYSLOG is that it
* cannot handle debug output generated from interrupt level handlers.
* (5) Any debug output generated from the IDLE loop. The character
* driver interface is blocking and the IDLE thread is not permitted
* to block.
* (6) If an irrecoverable failure occurred during initialization. In
* this case, we won't ever bother to try again (ever).
*
* NOTE: That the third case is different. It applies only to the thread
* that currently holds the sl_sem sempaphore. Other threads should wait.
* that is why that case is handled in syslog_semtake().
*/
/* Check if the system is ready to do output operations */
/* Cases (4) and (5) */
if (up_interrupt_context() || getpid() == 0)
ret = syslog_dev_outputready();
if (ret < 0)
{
errcode = ENOSYS;
errcode = -ret;
goto errout_with_errcode;
}
/* We can save checks in the usual case: That after the SYSLOG device
* has been successfully opened.
*/
if (g_syslog_dev.sl_state != SYSLOG_OPENED)
{
/* Case (1) and (2) */
if (g_syslog_dev.sl_state == SYSLOG_UNINITIALIZED ||
g_syslog_dev.sl_state == SYSLOG_INITIALIZING)
{
errcode = EAGAIN; /* Can't access the SYSLOG now... maybe next time? */
goto errout_with_errcode;
}
/* Case (6) */
if (g_syslog_dev.sl_state == SYSLOG_FAILURE)
{
errcode = ENXIO; /* There is no SYSLOG device */
goto errout_with_errcode;
}
/* syslog_dev_initialize() is called as soon as enough of the operating
* system is in place to support the open operation... but it is
* possible that the SYSLOG device is not yet registered at that time.
* In this case, we know that the system is sufficiently initialized
* to support an attempt to re-open the SYSLOG device.
*
* NOTE that the scheduler is locked. That is because we do not have
* fully initialized semaphore capability until the SYSLOG device is
* successfully initialized
*/
sched_lock();
if (g_syslog_dev.sl_state == SYSLOG_REOPEN)
{
/* Try again to initialize the device. We may do this repeatedly
* because the log device might be something that was not ready
* the first time that syslog_dev_initializee() was called (such as a
* USB serial device that has not yet been connected or a file in
* an NFS mounted file system that has not yet been mounted).
*/
DEBUGASSERT(g_syslog_dev.sl_devpath != NULL);
ret = syslog_dev_initialize(g_syslog_dev.sl_devpath,
(int)g_syslog_dev.sl_oflags,
(int)g_syslog_dev.sl_mode);
if (ret < 0)
{
sched_unlock();
errcode = -ret;
goto errout_with_errcode;
}
}
sched_unlock();
DEBUGASSERT(g_syslog_dev.sl_state == SYSLOG_OPENED);
}
/* Ignore carriage returns */
if (ch == '\r')

View File

@ -99,7 +99,7 @@ static void emergstream_putc(FAR struct lib_outstream_s *this, int ch)
*
* Input parameters:
* stream - User allocated, uninitialized instance of struct
* lib_lowoutstream_s to be initialized.
* lib_outstream_s to be initialized.
*
* Returned Value:
* None (User allocated instance initialized).

View File

@ -72,6 +72,9 @@ static int syslog_file_force(int ch);
static const struct syslog_channel_s g_syslog_file_channel =
{
#ifdef CONFIG_SYSLOG_WRITE
syslog_dev_write,
#endif
syslog_dev_putc,
syslog_file_force,
syslog_dev_flush,

View File

@ -1,7 +1,7 @@
/****************************************************************************
* drivers/syslog/syslog_stream.c
*
* Copyright (C) 2012, 2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2012, 2016-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -59,6 +59,24 @@
static void syslogstream_putc(FAR struct lib_outstream_s *this, int ch)
{
#ifdef CONFIG_SYSLOG_BUFFER
FAR struct lib_syslogstream_s *stream = (FAR struct lib_syslogstream_s *)this;
/* Add the incoming character to the buffer */
stream->buf[stream->nbuf] = ch;
stream->nbuf++;
this->nput++;
/* Is the buffer full? Did we encounter a new line? */
if (stream->nbuf >= CONFIG_SYSLOG_BUFSIZE || ch == '\n')
{
/* Yes.. then flush the buffer */
(void)this->flush(this);
}
#else
int ret;
/* Try writing until the write was successful or until an irrecoverable
@ -83,9 +101,46 @@ static void syslogstream_putc(FAR struct lib_outstream_s *this, int ch)
* ignored in this context.
*/
}
while (errno == -EINTR);
while (get_errno() == -EINTR);
#endif
}
/****************************************************************************
* Name: syslogstream_flush
****************************************************************************/
#ifdef CONFIG_SYSLOG_BUFFER
static int syslogstream_flush(FAR struct lib_outstream_s *this)
{
FAR struct lib_syslogstream_s *stream = (FAR struct lib_syslogstream_s *)this;
int ret = OK;
/* Is there anything buffered? */
if (stream->nbuf > 0)
{
/* Yes write the buffered data */
do
{
int status = syslog_write(stream->buf, stream->nbuf);
if (status < 0)
{
ret = -get_errno();
}
else
{
stream->nbuf = 0;
ret = OK;
}
}
while (ret == -EINTR);
}
return ret;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -99,16 +154,23 @@ static void syslogstream_putc(FAR struct lib_outstream_s *this, int ch)
*
* Input parameters:
* stream - User allocated, uninitialized instance of struct
* lib_lowoutstream_s to be initialized.
* lib_syslogstream_s to be initialized.
*
* Returned Value:
* None (User allocated instance initialized).
*
****************************************************************************/
void syslogstream(FAR struct lib_outstream_s *stream)
void syslogstream(FAR struct lib_syslogstream_s *stream)
{
stream->put = syslogstream_putc;
stream->flush = lib_noflush;
stream->nput = 0;
#ifdef CONFIG_SYSLOG_BUFFER
stream->public.put = syslogstream_putc;
stream->public.flush = syslogstream_flush;
stream->public.nput = 0;
stream->nbuf = 0;
#else
stream->public.put = syslogstream_putc;
stream->public.flush = lib_noflush;
stream->public.nput = 0;
#endif
}

View File

@ -0,0 +1,107 @@
/****************************************************************************
* drivers/syslog/syslog_write.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <nuttx/syslog/syslog.h>
#include "syslog.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: syslog_default_write
*
* Description:
* This provides a default write method for syslog devices that do not
* support multiple byte writes This functions simply loops, outputting
* one cahracter at a time.
*
* Input Parameters:
* buffer - The buffer containing the data to be output
* buflen - The number of bytes in the buffer
*
* Returned Value:
* On success, the number of characters written is returned. A negated
* errno value is returned on any failure.
*
****************************************************************************/
ssize_t syslog_default_write(FAR const char *buffer, size_t buflen)
{
size_t nwritten;
int ret;
for (nwritten = 0; nwritten < buflen; nwritten++)
{
int ch = *buffer++;
ret = syslog_putc(ch);
UNUSED(ret);
}
return buflen;
}
/****************************************************************************
* Name: syslog_write
*
* Description:
* This is the low-level, multiple character, system logging interface.
*
* Input Parameters:
* buffer - The buffer containing the data to be output
* buflen - The number of bytes in the buffer
*
* Returned Value:
* On success, the number of characters written is returned. A negated
* errno value is returned on any failure.
*
****************************************************************************/
ssize_t syslog_write(FAR const char *buffer, size_t buflen)
{
#ifdef CONFIG_SYSLOG_WRITE
return g_syslog_channel->sc_write(buffer, buflen);
#else
return syslog_default_write(buffer, buflen);
#endif
}

View File

@ -67,7 +67,7 @@
int _vsyslog(int priority, FAR const IPTR char *fmt, FAR va_list *ap)
{
struct lib_outstream_s stream;
struct lib_syslogstream_s stream;
#ifdef CONFIG_SYSLOG_TIMESTAMP
struct timespec ts;
int ret = -1;
@ -114,7 +114,7 @@ int _vsyslog(int priority, FAR const IPTR char *fmt, FAR va_list *ap)
{
/* Use the normal SYSLOG stream */
syslogstream((FAR struct lib_outstream_s *)&stream);
syslogstream((FAR struct lib_syslogstream_s *)&stream);
}
#if defined(CONFIG_SYSLOG_TIMESTAMP)

View File

@ -189,6 +189,18 @@ struct lib_rawsostream_s
int fd;
};
/* This is a special stream that does buffered character I/O. NOTE that is
* CONFIG_SYSLOG_BUFFER is not defined, it is the same as struct lib_outstream_s */
struct lib_syslogstream_s
{
struct lib_outstream_s public;
#ifdef CONFIG_SYSLOG_BUFFER
unsigned int nbuf;
char buf[CONFIG_SYSLOG_BUFSIZE];
#endif
};
/****************************************************************************
* Public Data
****************************************************************************/
@ -360,7 +372,7 @@ void lib_nulloutstream(FAR struct lib_outstream_s *nulloutstream);
*
****************************************************************************/
void syslogstream(FAR struct lib_outstream_s *stream);
void syslogstream(FAR struct lib_syslogstream_s *stream);
/****************************************************************************
* Name: emergstream

View File

@ -43,6 +43,8 @@
#include <nuttx/config.h>
#include <nuttx/compiler.h>
#include <sys/types.h>
#include <stdarg.h>
/****************************************************************************
@ -104,6 +106,7 @@ enum syslog_init_e
/* This structure provides the interface to a SYSLOG device */
typedef CODE ssize_t (*syslog_write_t)(FAR const char *buf, size_t buflen);
typedef CODE int (*syslog_putc_t)(int ch);
typedef CODE int (*syslog_flush_t)(void);
@ -111,8 +114,11 @@ struct syslog_channel_s
{
/* I/O redirection methods */
syslog_putc_t sc_putc; /* Normal buffered output */
syslog_putc_t sc_force; /* Low-level output for interrupt handlers */
#ifdef CONFIG_SYSLOG_WRITE
syslog_write_t sc_write; /* Write multiple bytes */
#endif
syslog_putc_t sc_putc; /* Normal buffered output */
syslog_putc_t sc_force; /* Low-level output for interrupt handlers */
syslog_flush_t sc_flush; /* Flush buffered output (on crash) */
/* Implementation specific logic may follow */