aboutsummaryrefslogtreecommitdiffstats
path: root/libparc/parc/logging
diff options
context:
space:
mode:
Diffstat (limited to 'libparc/parc/logging')
-rwxr-xr-xlibparc/parc/logging/parc_Log.c241
-rw-r--r--libparc/parc/logging/parc_Log.h418
-rw-r--r--libparc/parc/logging/parc_LogEntry.c162
-rwxr-xr-xlibparc/parc/logging/parc_LogEntry.h274
-rwxr-xr-xlibparc/parc/logging/parc_LogFormatSyslog.c122
-rwxr-xr-xlibparc/parc/logging/parc_LogFormatSyslog.h31
-rwxr-xr-xlibparc/parc/logging/parc_LogFormatText.c51
-rwxr-xr-xlibparc/parc/logging/parc_LogFormatText.h31
-rwxr-xr-xlibparc/parc/logging/parc_LogLevel.c92
-rwxr-xr-xlibparc/parc/logging/parc_LogLevel.h132
-rwxr-xr-xlibparc/parc/logging/parc_LogManager.c55
-rwxr-xr-xlibparc/parc/logging/parc_LogManager.h91
-rwxr-xr-xlibparc/parc/logging/parc_LogReporter.c71
-rwxr-xr-xlibparc/parc/logging/parc_LogReporter.h145
-rwxr-xr-xlibparc/parc/logging/parc_LogReporterFile.c62
-rwxr-xr-xlibparc/parc/logging/parc_LogReporterFile.h112
-rwxr-xr-xlibparc/parc/logging/parc_LogReporterTextStdout.c66
-rwxr-xr-xlibparc/parc/logging/parc_LogReporterTextStdout.h102
-rw-r--r--libparc/parc/logging/test/.gitignore12
-rw-r--r--libparc/parc/logging/test/CMakeLists.txt20
-rw-r--r--libparc/parc/logging/test/test_parc_Log.c345
-rw-r--r--libparc/parc/logging/test/test_parc_LogEntry.c465
-rwxr-xr-xlibparc/parc/logging/test/test_parc_LogFormatSyslog.c97
-rw-r--r--libparc/parc/logging/test/test_parc_LogFormatText.c95
-rwxr-xr-xlibparc/parc/logging/test/test_parc_LogLevel.c138
-rw-r--r--libparc/parc/logging/test/test_parc_LogReporter.c164
-rwxr-xr-xlibparc/parc/logging/test/test_parc_LogReporterFile.c149
-rwxr-xr-xlibparc/parc/logging/test/test_parc_LogReporterTextStdout.c128
28 files changed, 3871 insertions, 0 deletions
diff --git a/libparc/parc/logging/parc_Log.c b/libparc/parc/logging/parc_Log.c
new file mode 100755
index 00000000..e3948c36
--- /dev/null
+++ b/libparc/parc/logging/parc_Log.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <sys/time.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/logging/parc_Log.h>
+#include <parc/logging/parc_LogReporter.h>
+
+struct PARCLog {
+ char *hostName;
+ char *applicationName;
+ char *processId;
+ uint64_t messageId;
+ PARCLogLevel level;
+ PARCLogReporter *reporter;
+};
+
+static void
+_parcLogger_Destroy(PARCLog **loggerPtr)
+{
+ PARCLog *logger = *loggerPtr;
+
+ parcMemory_Deallocate((void **) &logger->hostName);
+ parcMemory_Deallocate((void **) &logger->applicationName);
+ parcMemory_Deallocate((void **) &logger->processId);
+ parcLogReporter_Release(&logger->reporter);
+}
+
+parcObject_ExtendPARCObject(PARCLog, _parcLogger_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+static const char *_nilvalue = "-";
+
+PARCLog *
+parcLog_Create(const char *hostName, const char *applicationName, const char *processId, PARCLogReporter *reporter)
+{
+ if (applicationName == NULL) {
+ applicationName = _nilvalue;
+ }
+ if (hostName == NULL) {
+ hostName = _nilvalue;
+ }
+ if (processId == NULL) {
+ processId = _nilvalue;
+ }
+
+ PARCLog *result = parcObject_CreateInstance(PARCLog);
+ if (result == NULL) {
+ trapOutOfMemory("Creating an instance of PARCLog.");
+ }
+
+ result->hostName = parcMemory_StringDuplicate(hostName, strlen(hostName));
+ result->applicationName = parcMemory_StringDuplicate(applicationName, strlen(applicationName));
+ result->processId = parcMemory_StringDuplicate(processId, strlen(processId));
+ result->messageId = 0;
+ result->level = PARCLogLevel_Off;
+ result->reporter = parcLogReporter_Acquire(reporter);
+ return result;
+}
+
+parcObject_ImplementAcquire(parcLog, PARCLog);
+
+parcObject_ImplementRelease(parcLog, PARCLog);
+
+
+PARCLogLevel
+parcLog_GetLevel(const PARCLog *log)
+{
+ return log->level;
+}
+
+PARCLogLevel
+parcLog_SetLevel(PARCLog *logger, const PARCLogLevel level)
+{
+ PARCLogLevel oldLevel = logger->level;
+ logger->level = level;
+ return oldLevel;
+}
+
+static PARCLogEntry *
+_parcLog_CreateEntry(PARCLog *log, PARCLogLevel level, uint64_t messageId, const char *format, va_list ap)
+{
+ char *cString;
+ int nwritten = vasprintf(&cString, format, ap);
+ assertTrue(nwritten >= 0, "Error calling vasprintf");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+
+ PARCBuffer *payload = parcBuffer_AllocateCString(cString);
+ PARCLogEntry *result = parcLogEntry_Create(level,
+ log->hostName,
+ log->applicationName,
+ log->processId,
+ messageId,
+ timeStamp,
+ payload);
+ parcBuffer_Release(&payload);
+
+ free(cString);
+ return result;
+}
+
+bool
+parcLog_MessageVaList(PARCLog *log, PARCLogLevel level, uint64_t messageId, const char *format, va_list ap)
+{
+ bool result = false;
+
+ if (parcLog_IsLoggable(log, level)) {
+ PARCLogEntry *entry = _parcLog_CreateEntry(log, level, messageId, format, ap);
+
+ parcLogReporter_Report(log->reporter, entry);
+ parcLogEntry_Release(&entry);
+ result = true;
+ }
+ return result;
+}
+
+bool
+parcLog_Message(PARCLog *log, PARCLogLevel level, uint64_t messageId, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(log, level, messageId, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Warning(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Warning, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Info(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Info, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Notice(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Notice, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Debug(PARCLog *logger, const char *format, ...)
+{
+ bool result = false;
+
+ if (parcLog_IsLoggable(logger, PARCLogLevel_Debug)) {
+ va_list ap;
+ va_start(ap, format);
+ result = parcLog_MessageVaList(logger, PARCLogLevel_Debug, 0, format, ap);
+ va_end(ap);
+ }
+
+ return result;
+}
+
+bool
+parcLog_Error(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Error, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Critical(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Critical, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Alert(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Alert, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
+
+bool
+parcLog_Emergency(PARCLog *logger, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ bool result = parcLog_MessageVaList(logger, PARCLogLevel_Emergency, 0, format, ap);
+ va_end(ap);
+
+ return result;
+}
diff --git a/libparc/parc/logging/parc_Log.h b/libparc/parc/logging/parc_Log.h
new file mode 100644
index 00000000..29e401e0
--- /dev/null
+++ b/libparc/parc/logging/parc_Log.h
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ * @file parc_Log.h
+ * @brief Event logging.
+ *
+ * This is an logging mechanism patterned after the Syslog logging protocol (RFC 5424),
+ * and influenced by `java.util.logging` and Apache Log4J.
+ *
+ * The lifecycle of a `PARCLog` starts with creating an instance via `parcLog_Create`
+ * and calling the various functions to emit log messages.
+ *
+ * Finally the log is released via `parcLog_Release` which ensures
+ * that any queued log messages are transmitted and resources are released.
+ *
+ * Every PARCLog instance has a logging level, a threshold that is set via `parcLog_SetLevel`
+ * that determines what kind of PARCLogEntry instances are actually logged.
+ * The PARCLogLevel PARCLogLevel_Emergency is always logged regardless of the current logging level.
+ *
+ */
+#ifndef libparc_parc_Logger_h
+#define libparc_parc_Logger_h
+
+#include <stdarg.h>
+
+#include <parc/logging/parc_LogReporter.h>
+#include <parc/logging/parc_LogEntry.h>
+#include <parc/logging/parc_LogLevel.h>
+
+struct PARCLog;
+typedef struct PARCLog PARCLog;
+
+/**
+ * Create a valid PARCLog instance.
+ *
+ * The initial instance's log level is set to `PARCLogLevel_Off`.
+ *
+ * @param [in] hostName A pointer to a nul-terminated C string, or NULL (See {@link PARCLogEntry}).
+ * @param [in] applicationName A pointer to a nul-terminated C string, or NULL (See {@link PARCLogEntry}).
+ * @param [in] processId A pointer to a nul-terminated C string, or NULL (See {@link PARCLogEntry}).
+ * @param [in] reporter A pointer to a valid `PARCLogReporter` instance.
+ *
+ * @return non-NULL A valid PARCLog instance.
+ * @return NULL An error occurred.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ * parcLogReporter_Release(&reporter);
+ * }
+ * @endcode
+ */
+PARCLog *parcLog_Create(const char *hostName, const char *applicationName, const char *processId, PARCLogReporter *reporter);
+
+/**
+ * Increase the number of references to a `PARCLog`.
+ *
+ * Note that new `PARCLog` is not created,
+ * only that the given `PARCLog` reference count is incremented.
+ * Discard the reference by invoking `parcLog_Release`.
+ *
+ * @param [in] parcLog A pointer to a `PARCLog` instance.
+ *
+ * @return The input `PARCLog` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ *
+ * PARCLog *x_2 = parcLog_Acquire(log);
+ *
+ * parcLog_Release(&log);
+ * parcLog_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLog *parcLog_Acquire(const PARCLog *parcLog);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] logPtr A pointer to a PARCLog instance pointer, which will be set to zero on return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ * parcLogReporter_Release(&reporter);
+ *
+ * parcLog_Release(&log);
+ * }
+ * @endcode
+ */
+void parcLog_Release(PARCLog **logPtr);
+
+/**
+ * Set the log severity level to the given value.
+ *
+ * The level is the maximum severity that will be logged via the PARCLogReporter.
+ * The log severity PARCLogLevel_Emergency cannot be blocked.
+ *
+ * @param [in] log A pointer to valid instance of PARCLog.
+ * @param [in] level A pointer to valid instance of PARCLogLevel.
+ *
+ * @return The previous value of the threshold.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ * parcLogReporter_Release(&reporter);
+ *
+ * PARCLogLevel old = parcLog_SetLevel(log, PARCLogLevel_Warning);
+ *
+ * parcLog_SetLevel(log, old);
+ *
+ * parcLog_Release(&log);
+ * }
+ * @endcode
+ */
+PARCLogLevel parcLog_SetLevel(PARCLog *log, const PARCLogLevel level);
+
+/**
+ * Get the severity level of the given PARCLog instance.
+ *
+ * The level is the maximum severity that will be logged via the PARCLogReporter.
+ * The log severity PARCLogLevel_Emergency cannot be blocked.
+ *
+ * @param [in] log A pointer to valid instance of PARCLog.
+ *
+ * @return The severity level of the given PARCLog instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ * parcLogReporter_Release(&reporter);
+ *
+ * PARCLogLevel level = parcLog_GetLevel(log, PARCLogLevel_Warning);
+ *
+ * parcLog_Release(&log);
+ * }
+ * @endcode
+ */
+PARCLogLevel parcLog_GetLevel(const PARCLog *log);
+
+/**
+ * Test if a PARCLogLevel would be logged by the current state of the given PARCLog instance.
+ *
+ * @param [in] log A pointer to valid instance of PARCLog.
+ * @param [in] level An instance of PARCLogLevel.
+ *
+ * @return true A PARCLogEntry of the given level would be logged.
+ * @return false A PARCLogEntry of the given level would be logged.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(1);
+ * PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ *
+ * parcOutputStream_Release(&output);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLog *log = parcLog_Create("localhost", "myApp", "daemon", reporter);
+ * parcLogReporter_Release(&reporter);
+ *
+ * if (parcLog_IsLoggable(log, PARCLogLevel_Warning)) {
+ * printf("Logging is set to Warning severity level\n");
+ * }
+ *
+ * parcLog_Release(&log);
+ * }
+ * @endcode
+ */
+
+#define parcLog_IsLoggable(_log_, _level_) \
+ (_level_ == PARCLogLevel_Emergency) || (parcLogLevel_Compare(parcLog_GetLevel(_log_), _level_) >= 0)
+//bool parcLog_IsLoggable(const PARCLog *log, const PARCLogLevel level);
+
+/**
+ * Compose and emit a log message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] level An instance of PARCLogLevel.
+ * @param [in] messageId A value for the message identifier.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ap A `va_list` representing the parameters for the format specification.
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower than the specified PARCLogLevel.
+ *
+ * Example:
+ * @code
+ * parcLog_MessageVaList(log, PARCLogLevel_Warning, 123, "This is a warning message.");
+ * @endcode
+ */
+bool parcLog_MessageVaList(PARCLog *log, PARCLogLevel level, uint64_t messageId, const char *format, va_list ap);
+
+/**
+ * Compose and emit a log message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] level An instance of PARCLogLevel.
+ * @param [in] messageId A value for the message identifier.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower than the specified PARCLogLevel.
+ *
+ * Example:
+ * @code
+ * parcLog_Message(log, PARCLogLevel_Warning, "This is a warning message.");
+ * @endcode
+ */
+bool parcLog_Message(PARCLog *log, PARCLogLevel level, uint64_t messageId, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Warning message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_Warning(log, "This is a warning message.");
+ * @endcode
+ */
+bool parcLog_Warning(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Message level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_Info(log, "This is an info message.");
+ * @endcode
+ */
+bool parcLog_Info(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Notice level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_Notice(log, "This is a notice message.");
+ * @endcode
+ */
+bool parcLog_Notice(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Debug level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_DebugMessage(log, "This is a debug message.");
+ * @endcode
+ */
+bool parcLog_Debug(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Error level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_ErrorMessage(log, "This is an error message.");
+ * @endcode
+ */
+bool parcLog_Error(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Critical level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_CriticalMessage(log, "This is a critical message.");
+ * @endcode
+ */
+bool parcLog_Critical(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Alert level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_AlertMessage(log, "This is an alert message.");
+ * @endcode
+ */
+bool parcLog_Alert(PARCLog *log, const char *restrict format, ...);
+
+/**
+ * Compose and emit a PARCLogLevel_Emergency level message.
+ *
+ * @param [in] log A pointer to a valid PARCLog instance.
+ * @param [in] format A pointer to a nul-terminated C string containing a printf format specification.
+ * @param [in] ... Zero or more parameters as input for the format specification).
+ *
+ * @return true The message was logged.
+ * @return false The message was not logged because the log severity threshold level is lower.
+ *
+ * Example:
+ * @code
+ * parcLog_EmergencyMessage(log, "This is an emergency message.");
+ * @endcode
+ */
+bool parcLog_Emergency(PARCLog *log, const char *restrict format, ...);
+#endif // libparc_parc_Logger_h
diff --git a/libparc/parc/logging/parc_LogEntry.c b/libparc/parc/logging/parc_LogEntry.c
new file mode 100644
index 00000000..f84e3719
--- /dev/null
+++ b/libparc/parc/logging/parc_LogEntry.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <inttypes.h>
+#include <stdarg.h>
+
+#include <parc/logging/parc_LogEntry.h>
+
+#include <parc/algol/parc_Time.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/logging/parc_LogLevel.h>
+
+static const char _parcLog_Version = 1;
+
+struct PARCLogEntry {
+ PARCLogLevel level;
+ char version;
+ struct timeval timeStamp;
+ char *hostName;
+ char *applicationName;
+ char *processName;
+ uint64_t messageId;
+
+ PARCBuffer *payload;
+};
+
+static void
+_parcLogEntry_Destroy(PARCLogEntry **entryPtr)
+{
+ PARCLogEntry *entry = *entryPtr;
+
+ parcMemory_Deallocate((void **) &entry->hostName);
+ parcMemory_Deallocate((void **) &entry->applicationName);
+ parcMemory_Deallocate((void **) &entry->processName);
+ parcBuffer_Release(&entry->payload);
+}
+
+static char *
+_toString(const PARCLogEntry *entry)
+{
+ PARCBufferComposer *composer = parcBufferComposer_Create();
+
+ parcBufferComposer_Format(composer, "%ld.%06d %d ",
+ (long) entry->timeStamp.tv_sec, (int) entry->timeStamp.tv_usec, entry->level);
+
+ size_t position = parcBuffer_Position(entry->payload);
+ parcBufferComposer_PutBuffer(composer, entry->payload);
+ parcBuffer_SetPosition(entry->payload, position);
+
+ PARCBuffer *buffer = parcBufferComposer_GetBuffer(composer);
+ parcBuffer_Rewind(buffer);
+
+ char *result = parcBuffer_ToString(buffer);
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
+
+parcObject_ExtendPARCObject(PARCLogEntry, _parcLogEntry_Destroy, NULL, _toString, NULL, NULL, NULL, NULL);
+
+PARCLogEntry *
+parcLogEntry_Create(PARCLogLevel level,
+ const char *hostName,
+ const char *applicationName,
+ const char *processName,
+ const uint64_t messageId,
+ const struct timeval timeStamp,
+ PARCBuffer *payload)
+{
+ PARCLogEntry *result = parcObject_CreateInstance(PARCLogEntry);
+ if (result == NULL) {
+ trapOutOfMemory("Creating an instance of PARCLogEntry.");
+ }
+ result->version = _parcLog_Version;
+ result->timeStamp = timeStamp;
+ result->hostName = parcMemory_StringDuplicate(hostName, strlen(hostName));
+ result->applicationName = parcMemory_StringDuplicate(applicationName, strlen(applicationName));
+ result->processName = parcMemory_StringDuplicate(processName, strlen(processName));
+ result->messageId = messageId;
+ result->level = level;
+ result->payload = parcBuffer_Acquire(payload);
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcLogEntry, PARCLogEntry);
+
+parcObject_ImplementRelease(parcLogEntry, PARCLogEntry);
+
+PARCBuffer *
+parcLogEntry_GetPayload(const PARCLogEntry *instance)
+{
+ return instance->payload;
+}
+
+const struct timeval *
+parcLogEntry_GetTimeStamp(const PARCLogEntry *instance)
+{
+ return &instance->timeStamp;
+}
+
+PARCLogLevel
+parcLogEntry_GetLevel(const PARCLogEntry *instance)
+{
+ return instance->level;
+}
+
+int
+parcLogEntry_GetVersion(const PARCLogEntry *instance)
+{
+ return instance->version;
+}
+
+const char *
+parcLogEntry_GetHostName(const PARCLogEntry *instance)
+{
+ return instance->hostName;
+}
+
+const char *
+parcLogEntry_GetApplicationName(const PARCLogEntry *instance)
+{
+ return instance->applicationName;
+}
+
+const char *
+parcLogEntry_GetProcessName(const PARCLogEntry *instance)
+{
+ return instance->processName;
+}
+
+uint64_t
+parcLogEntry_GetMessageId(const PARCLogEntry *instance)
+{
+ return instance->messageId;
+}
+
+char *
+parcLogEntry_ToString(const PARCLogEntry *entry)
+{
+ return _toString(entry);
+}
diff --git a/libparc/parc/logging/parc_LogEntry.h b/libparc/parc/logging/parc_LogEntry.h
new file mode 100755
index 00000000..90f6c493
--- /dev/null
+++ b/libparc/parc/logging/parc_LogEntry.h
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ * @file parc_LogEntry.h
+ * @brief Basic Log Entry implementation
+ *
+ * PARCLogEntry instances contain logging information in a single message.
+ *
+ * Each instance contains:
+ * * A log level (see PARCLogLevel).
+ * * An integer version number denoting the version of the syslog protocol specification (1).
+ * * A timestamp representable as an RFC 3339 Timestamp.
+ * * A hostname identifing the machine that originally sent the message.
+ * * An application name identifing the device or application that originated the message.
+ * * A process identifier having specific meaning,
+ * except that a change in the value indicates there has been a discontinuity in a series of
+ * otherwise linear PARCLogEntry instances.
+ * * A message identifier as a string without further semantics other than identifing the type of message.
+ *
+ */
+#ifndef PARC_Library_parc_LogEntry_h
+#define PARC_Library_parc_LogEntry_h
+
+#include <stdlib.h>
+
+#include <parc/algol/parc_Buffer.h>
+#include <sys/time.h>
+
+struct PARCLogEntry;
+typedef struct PARCLogEntry PARCLogEntry;
+
+#include <parc/logging/parc_LogLevel.h>
+
+/**
+ * Create a PARCLogEntry instance.
+ *
+ * @param [in] level A log level (see PARCLogLevel).
+ * * An integer version number denoting the version of the syslog protocol specification (1).
+ * @param [in] timeStamp The timestamp for the PARCLogEntry.
+ * @param [in] hostName The hostname identifing the machine that originally sent the message.
+ * @param [in] applicationName The application name identifing the device or application that originated the message.
+ * @param [in] processId An identifier having no specific meaning,
+ * except that a change in the value indicates there has been a discontinuity in a series of
+ * otherwise linear PARCLogEntry instances.
+ * @param [in] messageId A message identifier for the type of message.
+ * @param [in] payload The message component of the LogEntry.
+ *
+ * @return non-NULL A valid instance of PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCLogEntry *parcLogEntry_Create(PARCLogLevel level,
+ const char *hostName,
+ const char *applicationName,
+ const char *processId,
+ const uint64_t messageId,
+ const struct timeval timeStamp,
+ PARCBuffer *payload);
+
+/**
+ * Increase the number of references to a `PARCLogEntry` instance.
+ *
+ * Note that new `PARCLogEntry` is not created,
+ * only that the given `PARCLogEntry` reference count is incremented.
+ * Discard the reference by invoking `parcLogEntry_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCLogEntry` instance.
+ *
+ * @return The input `PARCLogEntry` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogEntry *x = parcLogEntry_Create(...);
+ *
+ * PARCLogEntry *x_2 = parcLogEntry_Acquire(x);
+ *
+ * parcLogEntry_Release(&x);
+ * parcLogEntry_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLogEntry *parcLogEntry_Acquire(const PARCLogEntry *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] entryPtr A pointer to a pointer to a PARCLogEntry. The parameter is set to zero.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogEntry *entry = parcLogEntry_Create(...)
+ *
+ * parcLogEntry_Release(&entry);
+ * }
+ * @endcode
+ */
+void parcLogEntry_Release(PARCLogEntry **entryPtr);
+
+/**
+ * Produce a null-terminated string representation of the specified instance.
+ *
+ * The result must be freed by the caller via {@link parcMemory_Deallocate}.
+ *
+ * @param [in] entry A pointer to the instance.
+ *
+ * @return NULL Cannot allocate memory.
+ * @return non-NULL A pointer to an allocated, null-terminated C string that must be deallocated via {@link parcMemory_Deallocate}.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogEntry *entry = parcLogEntry_Create(...)
+ *
+ * char *string = parcLogEntry_ToString(entry);
+ * printf("%s\n", string);
+ * parcMemory_Deallocate(&string);
+ *
+ * parcLogEntry_Release(&entry);
+ * }
+ * @endcode
+ *
+ */
+char *parcLogEntry_ToString(const PARCLogEntry *entry);
+
+/**
+ * Get the payload of the specified PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return A pointer to the payload of the PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+PARCBuffer *parcLogEntry_GetPayload(const PARCLogEntry *instance);
+
+/**
+ * Get the timestamp of the specified PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return A pointer to the struct timeval of the PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+const struct timeval *parcLogEntry_GetTimeStamp(const PARCLogEntry *instance);
+
+/**
+ * Get the PARCLogLevel of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The PARCLogLevel of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+PARCLogLevel parcLogEntry_GetLevel(const PARCLogEntry *instance);
+
+/**
+ * Get the PARCLogLevel of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The version number of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+int parcLogEntry_GetVersion(const PARCLogEntry *instance);
+
+/**
+ * Get the host-name of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The application name of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcLogEntry_GetHostName(const PARCLogEntry *instance);
+
+/**
+ * Get the application-name of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The application name of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcLogEntry_GetApplicationName(const PARCLogEntry *instance);
+
+/**
+ * Get the process-id of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The process-id of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+const char *parcLogEntry_GetProcessName(const PARCLogEntry *instance);
+
+/**
+ * Get the message-id of the given PARCLogEntry.
+ *
+ * @param [in] instance A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return The message-id of the given PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * {
+ * <#example#>
+ * }
+ * @endcode
+ */
+uint64_t parcLogEntry_GetMessageId(const PARCLogEntry *instance);
+
+#endif
diff --git a/libparc/parc/logging/parc_LogFormatSyslog.c b/libparc/parc/logging/parc_LogFormatSyslog.c
new file mode 100755
index 00000000..2b3e7e9c
--- /dev/null
+++ b/libparc/parc/logging/parc_LogFormatSyslog.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <inttypes.h>
+
+#include <parc/logging/parc_LogFormatSyslog.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Time.h>
+
+/*
+ * RFC 5424
+ *
+ * SYSLOG-MSG = HEADER SP STRUCTURED-DATA [SP MSG]
+ *
+ * HEADER = PRI VERSION SP TIMESTAMP SP HOSTNAME SP APP-NAME SP PROCID SP MSGID
+ * PRI = "<" PRIVAL ">"
+ * PRIVAL = 1*3DIGIT ; range 0 .. 191
+ * VERSION = NONZERO-DIGIT 0*2DIGIT
+ * HOSTNAME = NILVALUE / 1*255PRINTUSASCII
+ *
+ * APP-NAME = NILVALUE / 1*48PRINTUSASCII
+ * PROCID = NILVALUE / 1*128PRINTUSASCII
+ * MSGID = NILVALUE / 1*32PRINTUSASCII
+ *
+ * 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
+ *
+ *
+ * STRUCTURED-DATA = NILVALUE / 1*SD-ELEMENT
+ * SD-ELEMENT = "[" SD-ID *(SP SD-PARAM) "]"
+ * SD-PARAM = PARAM-NAME "=" %d34 PARAM-VALUE %d34
+ * SD-ID = SD-NAME
+ * PARAM-NAME = SD-NAME
+ * PARAM-VALUE = UTF-8-STRING ; characters '"', '\' and ']' MUST be escaped.
+ * SD-NAME = 1*32PRINTUSASCII ; except '=', SP, ']', %d34 (")
+ *
+ * MSG = MSG-ANY / MSG-UTF8
+ * MSG-ANY = *OCTET ; not starting with BOM
+ * MSG-UTF8 = BOM UTF-8-STRING
+ * BOM = %xEF.BB.BF
+ *
+ *
+ * UTF-8-STRING = *OCTET ; UTF-8 string as specified in RFC 3629
+ *
+ * OCTET = %d00-255
+ * SP = %d32
+ * PRINTUSASCII = %d33-126
+ * NONZERO-DIGIT = %d49-57
+ * DIGIT = %d48 / NONZERO-DIGIT
+ * NILVALUE = "-"
+ */
+/**
+ * Create a PARCBuffer containing the PARCLogEntry formatted according to RFC 5424 section 6.
+ *
+ * The returned PARCBuffer's position is set to the start of the formatted data and continues to the limit.
+ *
+ * @param [in] entry A pointer to a valid instance of PARCLogEntry.
+ *
+ * @return non-NULL A pointer to a PARCBuffer containing the formatted PARCLogEntry.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ *
+ * @see parcLogEntry_ToString
+ */
+PARCBuffer *
+parcLogFormatSyslog_FormatEntry(const PARCLogEntry *entry)
+{
+ PARCBuffer *payload = parcLogEntry_GetPayload(entry);
+
+ char theTime[64];
+ parcTime_TimevalAsRFC3339(parcLogEntry_GetTimeStamp(entry), theTime);
+
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(128);
+
+ parcBufferComposer_Format(composer, "<%s> %d ",
+ parcLogLevel_ToString(parcLogEntry_GetLevel(entry)), parcLogEntry_GetVersion(entry));
+ parcBufferComposer_PutStrings(composer,
+ theTime, " ",
+ parcLogEntry_GetHostName(entry), " ",
+ parcLogEntry_GetApplicationName(entry), " ",
+ parcLogEntry_GetProcessName(entry), " ", NULL);
+
+ parcBufferComposer_Format(composer, "%" PRId64 " [ ", parcLogEntry_GetMessageId(entry));
+ parcBufferComposer_PutBuffer(composer, payload);
+ parcBufferComposer_PutStrings(composer, " ]\n", NULL);
+ PARCBuffer *result = parcBuffer_Flip(parcBuffer_Acquire(parcBufferComposer_GetBuffer(composer)));
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
diff --git a/libparc/parc/logging/parc_LogFormatSyslog.h b/libparc/parc/logging/parc_LogFormatSyslog.h
new file mode 100755
index 00000000..3ace4e7b
--- /dev/null
+++ b/libparc/parc/logging/parc_LogFormatSyslog.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ * @file parc_LogFormatSyslog.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef __PARC_Library__parc_LogFormatSyslog__
+#define __PARC_Library__parc_LogFormatSyslog__
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/logging/parc_LogEntry.h>
+
+PARCBuffer *parcLogFormatSyslog_FormatEntry(const PARCLogEntry *entry);
+
+#endif /* defined(__PARC_Library__parc_LogFormatSyslog__) */
diff --git a/libparc/parc/logging/parc_LogFormatText.c b/libparc/parc/logging/parc_LogFormatText.c
new file mode 100755
index 00000000..7497967b
--- /dev/null
+++ b/libparc/parc/logging/parc_LogFormatText.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <inttypes.h>
+
+#include <parc/logging/parc_LogFormatText.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Time.h>
+
+PARCBuffer *
+parcLogFormatText_FormatEntry(const PARCLogEntry *entry)
+{
+ PARCBuffer *payload = parcLogEntry_GetPayload(entry);
+
+ char theTime[64];
+ parcTime_TimevalAsRFC3339(parcLogEntry_GetTimeStamp(entry), theTime);
+
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(128);
+
+ parcBufferComposer_PutStrings(composer,
+ theTime, " ",
+ parcLogLevel_ToString(parcLogEntry_GetLevel(entry)), " ",
+ parcLogEntry_GetHostName(entry), " ",
+ parcLogEntry_GetApplicationName(entry), " ",
+ parcLogEntry_GetProcessName(entry), " ", NULL);
+
+ parcBufferComposer_Format(composer, "%" PRId64 " [ ", parcLogEntry_GetMessageId(entry));
+ parcBufferComposer_PutBuffer(composer, payload);
+ parcBufferComposer_PutStrings(composer, " ]\n", NULL);
+ PARCBuffer *result = parcBuffer_Flip(parcBuffer_Acquire(parcBufferComposer_GetBuffer(composer)));
+
+ parcBufferComposer_Release(&composer);
+
+ return result;
+}
diff --git a/libparc/parc/logging/parc_LogFormatText.h b/libparc/parc/logging/parc_LogFormatText.h
new file mode 100755
index 00000000..b4bb5b1f
--- /dev/null
+++ b/libparc/parc/logging/parc_LogFormatText.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ * @file parc_LogFormatText.h
+ * @brief <#Brief Description#>
+ *
+ * <#Detailed Description#>
+ *
+ */
+#ifndef __PARC_Library__parc_LogFormatText__
+#define __PARC_Library__parc_LogFormatText__
+
+#include <parc/algol/parc_Buffer.h>
+#include <parc/logging/parc_LogEntry.h>
+
+PARCBuffer *parcLogFormatText_FormatEntry(const PARCLogEntry *entry);
+
+#endif /* defined(__PARC_Library__parc_LogFormatText__) */
diff --git a/libparc/parc/logging/parc_LogLevel.c b/libparc/parc/logging/parc_LogLevel.c
new file mode 100755
index 00000000..62d07072
--- /dev/null
+++ b/libparc/parc/logging/parc_LogLevel.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ */
+#include <config.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <parc/logging/parc_LogLevel.h>
+
+const PARCLogLevel PARCLogLevel_Off = 0;
+
+const PARCLogLevel PARCLogLevel_All = 255;
+
+const PARCLogLevel PARCLogLevel_Emergency = 1;
+
+const PARCLogLevel PARCLogLevel_Alert = 2;
+
+const PARCLogLevel PARCLogLevel_Critical = 3;
+
+const PARCLogLevel PARCLogLevel_Error = 4;
+
+const PARCLogLevel PARCLogLevel_Warning = 5;
+
+const PARCLogLevel PARCLogLevel_Notice = 6;
+
+const PARCLogLevel PARCLogLevel_Info = 7;
+
+const PARCLogLevel PARCLogLevel_Debug = 8;
+
+static char *levelToString[] = {
+ "Off",
+ "Emergency",
+ "Alert",
+ "Critical",
+ "Error",
+ "Warning",
+ "Notice",
+ "Info",
+ "Debug",
+ NULL
+};
+
+//int
+//parcLogLevel_Compare(const PARCLogLevel levelA, const PARCLogLevel levelB)
+//{
+// return levelA - levelB;
+//}
+
+int
+parcLogLevel_Equals(const PARCLogLevel levelA, const PARCLogLevel levelB)
+{
+ return levelA == levelB;
+}
+
+
+PARCLogLevel
+parcLogLevel_FromString(const char *levelAsString)
+{
+ PARCLogLevel result = PARCLogLevel_All;
+ for (size_t i = 0; levelToString[i] != NULL; i++) {
+ if (strcasecmp(levelAsString, levelToString[i]) == 0) {
+ result = i;
+ }
+ }
+
+ return result;
+}
+
+const char *
+parcLogLevel_ToString(const PARCLogLevel level)
+{
+ char *result = "All";
+ if (level <= PARCLogLevel_Debug) {
+ result = levelToString[level];
+ }
+ return result;
+}
diff --git a/libparc/parc/logging/parc_LogLevel.h b/libparc/parc/logging/parc_LogLevel.h
new file mode 100755
index 00000000..4540924e
--- /dev/null
+++ b/libparc/parc/logging/parc_LogLevel.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ * @file parc_LogLevel.h
+ * @brief Logging levels for PARCLog
+ *
+ * A PARCLogLevel represents both the severity level of a particular PARCLogEntry,
+ * and the threshold of a particular PARCLog instance.
+ *
+ */
+#ifndef PARC_Library_parc_LogLevel_h
+#define PARC_Library_parc_LogLevel_h
+
+typedef unsigned char PARCLogLevel;
+
+/** OFF is a special level that can be used to turn off logging. */
+extern const PARCLogLevel PARCLogLevel_Off;
+
+/** ALL indicates that all messages should be logged. */
+extern const PARCLogLevel PARCLogLevel_All;
+
+/** PARCLogLevel_Emergency is a message level indicating the system is unusable. */
+extern const PARCLogLevel PARCLogLevel_Emergency;
+
+/** PARCLogLevel_Alert is a message level indicating action must be taken immediately to ensure correctness. */
+extern const PARCLogLevel PARCLogLevel_Alert;
+
+/** PARCLogLevel_Critical is a message level for critical conditions. */
+extern const PARCLogLevel PARCLogLevel_Critical;
+
+/** PARCLogLevel_Error is a message level reporting error conditions. */
+extern const PARCLogLevel PARCLogLevel_Error;
+
+/** PARCLogLevel_Warning indicates a fairly detailed tracing message. */
+extern const PARCLogLevel PARCLogLevel_Warning;
+
+/** FINEST indicates a normal but significant condition. */
+extern const PARCLogLevel PARCLogLevel_Notice;
+
+/** INFO is a message level for informational messages. */
+extern const PARCLogLevel PARCLogLevel_Info;
+
+/** INFO is a message level for debug-level messages. */
+extern const PARCLogLevel PARCLogLevel_Debug;
+
+/**
+ * Compare `PARCLogLevel` instances @p levelA and @p levelA for order.
+ *
+ * @param [in] levelA An instance of PARCLogLevel.
+ * @param [in] levelB An instance of PARCLogLevel.
+ *
+ * @return < 0 levelA is less than levelB
+ * @return == 0 levelA is equal to levelB
+ * @return > 0 levelA is greater than levelB
+ *
+ * Example:
+ * @code
+ * {
+ * int comparison = parcLogLevel_Compare(PARCLogLevel_Notice, PARCLogLevel_Notice);
+ * }
+ * @endcode
+ */
+#define parcLogLevel_Compare(_levelA_, _levelB_) (_levelA_ - _levelB_)
+//int parcLogLevel_Compare(const PARCLogLevel levelA, const PARCLogLevel levelB);
+
+/**
+ * Determine if two instances of PARCLogLevel are equal.
+ *
+ * @param [in] levelA An instance of PARCLogLevel.
+ * @param [in] levelB An instance of PARCLogLevel.
+ *
+ * @return true The instances are equal.
+ * @return false The instances are not equal.
+ *
+ * Example:
+ * @code
+ * {
+ * bool equal = parcLogLevel_Equals(PARCLogLevel_Notice, PARCLogLevel_Notice);
+ * }
+ * @endcode
+ */
+int parcLogLevel_Equals(const PARCLogLevel levelA, const PARCLogLevel levelB);
+
+/**
+ * Get the string representation of the PARCLogLevel;
+ *
+ * @param [in] level A valid PARCLogLevel
+ *
+ * @return A pointer to a constant, nul-terminated C string.
+ *
+ * Example:
+ * @code
+ * {
+ * const char * logLevelString = parcLogLevel_ToString(PARCLogLevel_Emergency);
+ * }
+ * @endcode
+ */
+const char *parcLogLevel_ToString(const PARCLogLevel level);
+
+/**
+ * Given a string representation of a logging level, return the corresponding PARCLogLevel value.
+ *
+ * The string is case insensitive.
+ *
+ * Unknown or uninterpretable strings return PARCLogLevel_All.
+ *
+ * @param [in] levelAsString A nul-terminated C string representation of the logging level.
+ *
+ * @return A valid PARCLogLevel.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogLevel level = parcLogLevel_FromString("Emergency");
+ * }
+ * @endcode
+ */
+PARCLogLevel parcLogLevel_FromString(const char *levelAsString);
+#endif
diff --git a/libparc/parc/logging/parc_LogManager.c b/libparc/parc/logging/parc_LogManager.c
new file mode 100755
index 00000000..28f24d07
--- /dev/null
+++ b/libparc/parc/logging/parc_LogManager.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <LongBow/runtime.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Memory.h>
+
+#include <parc/logging/parc_LogManager.h>
+
+struct PARCLogManager {
+ void *thisIsntFinishedYet;
+};
+
+#if 0
+static void
+_parcLogManager_Destroy(PARCLogManager **instancePtr)
+{
+ //PARCLogManager *instance = *instancePtr;
+}
+#endif
+
+PARCLogManager *
+parcLogManager_Create(void)
+{
+ return NULL;
+}
+
+PARCLogManager *
+parcLogManager_Acquire(const PARCLogManager *instance)
+{
+ return parcObject_Acquire(instance);
+}
+
+void
+parcLogManager_Release(PARCLogManager **instancePtr)
+{
+ parcObject_Release((void **) instancePtr);
+}
diff --git a/libparc/parc/logging/parc_LogManager.h b/libparc/parc/logging/parc_LogManager.h
new file mode 100755
index 00000000..ce50c60b
--- /dev/null
+++ b/libparc/parc/logging/parc_LogManager.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ * @file parc_LogManager.h
+ * @brief <#Brief Description#>
+ *
+ */
+#ifndef PARC_Library_parc_LogManager_h
+#define PARC_Library_parc_LogManager_h
+
+struct PARCLogManager;
+typedef struct PARCLogManager PARCLogManager;
+
+/**
+ * Create a new PARCLogManager
+ *
+ * @return non-NULL A pointer to a valid PARCLogManager
+ * @return NULL Out of memory.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogManager *manager = parcLogManager_Create();
+ *
+ * parcLogManager_Release(&manager);
+ * }
+ * @endcode
+ */
+PARCLogManager *parcLogManager_Create(void);
+
+/**
+ * Increase the number of references to a `PARCLogManager` instance.
+ *
+ * Note that new `PARCLogManager` is not created,
+ * only that the given `PARCLogManager` reference count is incremented.
+ * Discard the reference by invoking `parcLogManager_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCLogManager` instance.
+ *
+ * @return The input `PARCLogManager` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogManager *manager = parcLogManager_Create();
+ *
+ * PARCLogReporter *x_2 = parcLogManager_Acquire(reporter);
+ *
+ * parcLogManager_Release(&manager);
+ * parcLogManager_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLogManager *parcLogManager_Acquire(const PARCLogManager *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to a `PARCLogManager`. The parameter is set to zero.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogManager *manager = parcLogManager_Create();
+ *
+ * parcLogManager_Release(&manager);
+ * }
+ * @endcode
+ */
+void parcLogManager_Release(PARCLogManager **instancePtr);
+#endif
diff --git a/libparc/parc/logging/parc_LogReporter.c b/libparc/parc/logging/parc_LogReporter.c
new file mode 100755
index 00000000..a06f360a
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporter.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <parc/logging/parc_LogReporter.h>
+#include <parc/algol/parc_Object.h>
+
+struct PARCLogReporter {
+ PARCLogReporter *(*acquire)(const PARCLogReporter *);
+ void (*release)(PARCLogReporter **);
+ void (*report)(PARCLogReporter *, const PARCLogEntry *);
+
+ PARCObject *privateObject;
+};
+
+static void
+_parcLogReporter_Destroy(PARCLogReporter **reporterPtr __attribute__((unused)))
+{
+ PARCLogReporter *result = *reporterPtr;
+ if (result->privateObject != NULL) {
+ parcObject_Release(&result->privateObject);
+ }
+}
+
+parcObject_ExtendPARCObject(PARCLogReporter, _parcLogReporter_Destroy, NULL, NULL, NULL, NULL, NULL, NULL);
+
+PARCLogReporter *
+parcLogReporter_Create(PARCLogReporter *(*acquire)(const PARCLogReporter *),
+ void (*release)(PARCLogReporter **),
+ void (*report)(PARCLogReporter *, const PARCLogEntry *),
+ void *privateObject)
+{
+ PARCLogReporter *result = parcObject_CreateInstance(PARCLogReporter);
+ result->acquire = acquire;
+ result->release = release;
+ result->report = report;
+ result->privateObject = privateObject;
+
+ return result;
+}
+
+parcObject_ImplementAcquire(parcLogReporter, PARCLogReporter);
+
+parcObject_ImplementRelease(parcLogReporter, PARCLogReporter);
+
+void
+parcLogReporter_Report(PARCLogReporter *reporter, const PARCLogEntry *report)
+{
+ reporter->report(reporter, report);
+}
+
+void *
+parcLogReporter_GetPrivateObject(const PARCLogReporter *reporter)
+{
+ return reporter->privateObject;
+}
diff --git a/libparc/parc/logging/parc_LogReporter.h b/libparc/parc/logging/parc_LogReporter.h
new file mode 100755
index 00000000..65496f55
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporter.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ * @file parc_LogReporter.h
+ * @brief An abstract representation of a PARC Log Reporter.
+ *
+ */
+#ifndef PARC_Library_parc_LogReporter_h
+#define PARC_Library_parc_LogReporter_h
+
+#include <parc/logging/parc_LogEntry.h>
+
+typedef void (PARCLogReporterAcquire)(void *reporter);
+
+/**
+ * A Function that performs the final cleanup and resource deallocation when
+ * a PARCLogReporter is no longer needed.
+ */
+typedef void (PARCLogReporterRelease)(void **reporterP);
+
+/**
+ */
+typedef void (PARCLogReporterReport)(const PARCLogEntry *reporter);
+
+struct PARCLogReporter;
+typedef struct PARCLogReporter PARCLogReporter;
+
+/**
+ * Create a new instance of `PARCLogReporter` using the given the functions specified.
+ *
+ * @param [in] acquire A pointer to a function that performs the Aquire contract.
+ * @param [in] release A pointer to a function that performs the Release contract.
+ * @param [in] report A pointer to a function that performs the 'report' function.
+ * @param [in] privateObject A pointer to a PARCObject that is supplied to the report function when invoked, or NULL.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a valid `PARCLogReporter` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *result = parcLogReporter_Create(&parcLogReporterFile_Acquire,
+ * parcLogReporterFile_Release,
+ * parcLogReporterFile_Report,
+ * parcOutputStream_Acquire(output));
+ * return result;
+ * }
+ * @endcode
+ */
+PARCLogReporter *parcLogReporter_Create(PARCLogReporter *(*acquire)(const PARCLogReporter *),
+ void (*release)(PARCLogReporter **),
+ void (*report)(PARCLogReporter *, const PARCLogEntry *),
+ void *privateObject);
+
+/**
+ * Increase the number of references to a `PARCLogReporter` instance.
+ *
+ * Note that new `PARCLogReporter` is not created,
+ * only that the given `PARCLogReporter` reference count is incremented.
+ * Discard the reference by invoking `parcLogReporter_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCLogReporter` instance.
+ *
+ * @return The input `PARCLogReporter` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *reporter = parcLogReporter_Create(&parcLogReporterFile_Acquire,
+ * parcLogReporterFile_Release,
+ * parcLogReporterFile_Report,
+ * parcOutputStream_Acquire(output));
+ *
+ * PARCLogReporter *x_2 = parcLogReporter_Acquire(reporter);
+ *
+ * parcLogReporter_Release(&reporter);
+ * parcLogReporter_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLogReporter *parcLogReporter_Acquire(const PARCLogReporter *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] instancePtr A pointer to a pointer to a `PARCLogReporter`. The parameter is set to zero.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *reporter = parcLogReporter_Create(&parcLogReporterFile_Acquire,
+ * parcLogReporterFile_Release,
+ * parcLogReporterFile_Report,
+ * parcOutputStream_Acquire(output));
+ *
+ * parcLogReporter_Release(&reporter);
+ * }
+ * @endcode
+ */
+void parcLogReporter_Release(PARCLogReporter **instancePtr);
+
+/**
+ * Report the given PARCLogEntry
+ *
+ * @param [in] reporter A pointer to a valid PARCLogReporter instance.
+ * @param [in] entry A pointer to a valid PARCLogEntry instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcLogReporter_Report(PARCLogReporter *reporter, const PARCLogEntry *entry);
+
+/**
+ * Get the private PARCObject supplied when the PARCLogReporter was created.
+ *
+ * @param [in] reporter A valid PARCLogReporter instance.
+ *
+ * @return A same pointer supplied when the PARCLogReporter was created.
+ *
+ */
+void *parcLogReporter_GetPrivateObject(const PARCLogReporter *reporter);
+
+#endif
diff --git a/libparc/parc/logging/parc_LogReporterFile.c b/libparc/parc/logging/parc_LogReporterFile.c
new file mode 100755
index 00000000..d9bd4986
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporterFile.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ */
+#include <config.h>
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <parc/logging/parc_LogReporterFile.h>
+#include <parc/logging/parc_LogFormatSyslog.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_Time.h>
+
+#include <parc/algol/parc_FileOutputStream.h>
+
+PARCLogReporter *
+parcLogReporterFile_Create(PARCOutputStream *output)
+{
+ PARCLogReporter *result = parcLogReporter_Create(&parcLogReporterFile_Acquire,
+ parcLogReporterFile_Release,
+ parcLogReporterFile_Report,
+ parcOutputStream_Acquire(output));
+ return result;
+}
+
+PARCLogReporter *
+parcLogReporterFile_Acquire(const PARCLogReporter *reporter)
+{
+ return parcObject_Acquire(reporter);
+}
+
+void
+parcLogReporterFile_Release(PARCLogReporter **reporterP)
+{
+ parcObject_Release((void **) reporterP);
+}
+
+void
+parcLogReporterFile_Report(PARCLogReporter *reporter, const PARCLogEntry *entry)
+{
+ PARCOutputStream *output = parcLogReporter_GetPrivateObject(reporter);
+
+ PARCBuffer *formatted = parcLogFormatSyslog_FormatEntry(entry);
+ parcOutputStream_Write(output, formatted);
+ parcBuffer_Release(&formatted);
+}
diff --git a/libparc/parc/logging/parc_LogReporterFile.h b/libparc/parc/logging/parc_LogReporterFile.h
new file mode 100755
index 00000000..19bbae5d
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporterFile.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ * @file parc_LogReporterFile.h
+ * @brief <#Brief Description#>
+ *
+ */
+#ifndef __PARC_Library__parc_LogReporterFile__
+#define __PARC_Library__parc_LogReporterFile__
+
+#include <parc/logging/parc_LogReporter.h>
+#include <parc/algol/parc_OutputStream.h>
+
+/**
+ * Create a new instance of `PARCLogReporter` using the given {@link PARCOutputStream}.
+ *
+ * @param [in] output A pointer to a valid `PARCOutputStream` instance.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a valid `PARCLogReporter` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ * PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ * parcFileOutputStream_Release(&fileOutput);
+ *
+ * PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+ * parcOutputStream_Release(&out);
+ *
+ * parcLogReporter_Release(&reporter);
+ * }
+ * <#example#>
+ * @endcode
+ */
+PARCLogReporter *parcLogReporterFile_Create(PARCOutputStream *output);
+
+/**
+ * Increase the number of references to a `PARCLogReporter` instance.
+ *
+ * Note that new `PARCLogReporter` is not created,
+ * only that the given `PARCLogReporter` reference count is incremented.
+ * Discard the reference by invoking `parcLogEntry_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCLogReporter` instance.
+ *
+ * @return The input `PARCLogReporter` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *x = parcLogReporterFile_Create(...);
+ *
+ * PARCLogReporter *x_2 = parcLogReporterFile_Acquire(x);
+ *
+ * parcLogReporterFile_Release(&x);
+ * parcLogReporterFile_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLogReporter *parcLogReporterFile_Acquire(const PARCLogReporter *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] reporterP A pointer to a PARCLogReporter instance pointer, which will be set to zero on return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *x = parcLogReporterFile_Create(...);
+ *
+ * parcLogReporterFile_Release(&x);
+ * }
+ * @endcode
+ */
+void parcLogReporterFile_Release(PARCLogReporter **reporterP);
+
+/**
+ * Report the given PARCLogEntry
+ *
+ * @param [in] reporter A pointer to a valid PARCLogReporter instance.
+ * @param [in] entry A pointer to a valid PARCLogEntry instance.
+ *
+ * Example:
+ * @code
+ * <#example#>
+ * @endcode
+ */
+void parcLogReporterFile_Report(PARCLogReporter *reporter, const PARCLogEntry *entry);
+#endif /* defined(__PARC_Library__parc_LogReporterFile__) */
diff --git a/libparc/parc/logging/parc_LogReporterTextStdout.c b/libparc/parc/logging/parc_LogReporterTextStdout.c
new file mode 100755
index 00000000..86d5190e
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporterTextStdout.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ */
+#include <config.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <parc/algol/parc_Object.h>
+#include <parc/algol/parc_OutputStream.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/algol/parc_BufferComposer.h>
+#include <parc/algol/parc_Time.h>
+
+#include <parc/logging/parc_LogReporterTextStdout.h>
+#include <parc/logging/parc_LogFormatText.h>
+
+PARCLogReporter *
+parcLogReporterTextStdout_Create(void)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *result = parcLogReporter_Create(&parcLogReporterTextStdout_Acquire,
+ parcLogReporterTextStdout_Release,
+ parcLogReporterTextStdout_Report,
+ parcOutputStream_Acquire(out));
+ parcOutputStream_Release(&out);
+ return result;
+}
+
+PARCLogReporter *
+parcLogReporterTextStdout_Acquire(const PARCLogReporter *instance)
+{
+ return parcObject_Acquire(instance);
+}
+
+void
+parcLogReporterTextStdout_Release(PARCLogReporter **reporterP)
+{
+ parcObject_Release((void **) reporterP);
+}
+
+void
+parcLogReporterTextStdout_Report(PARCLogReporter *reporter, const PARCLogEntry *entry)
+{
+ PARCOutputStream *output = parcLogReporter_GetPrivateObject(reporter);
+
+ PARCBuffer *formatted = parcLogFormatText_FormatEntry(entry);
+ parcOutputStream_Write(output, formatted);
+ parcBuffer_Release(&formatted);
+}
diff --git a/libparc/parc/logging/parc_LogReporterTextStdout.h b/libparc/parc/logging/parc_LogReporterTextStdout.h
new file mode 100755
index 00000000..4365330e
--- /dev/null
+++ b/libparc/parc/logging/parc_LogReporterTextStdout.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/**
+ * @file parc_LogReporterTextStdout.h
+ * @brief A simple log reporter using plain text formatting to standard output.
+ *
+ */
+#ifndef PARC_Library_parc_LogReporterTextStdout_h
+#define PARC_Library_parc_LogReporterTextStdout_h
+
+#include <parc/logging/parc_LogReporter.h>
+
+/**
+ * Create a new instance of `PARCLogReporter` using standard output.
+ *
+ * @return NULL Memory could not be allocated.
+ * @return non-NULL A pointer to a valid `PARCLogReporter` instance.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ *
+ * parcLogReporter_Release(&reporter);
+ * }
+ * <#example#>
+ * @endcode
+ */
+PARCLogReporter *parcLogReporterTextStdout_Create(void);
+
+/**
+ * Increase the number of references to a `PARCLogReporter` instance.
+ *
+ * Note that new `PARCLogReporter` is not created,
+ * only that the given `PARCLogReporter` reference count is incremented.
+ * Discard the reference by invoking `parcLogEntry_Release`.
+ *
+ * @param [in] instance A pointer to a `PARCLogReporter` instance.
+ *
+ * @return The input `PARCLogReporter` pointer.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *x = parcLogReporterTextStdout_Create();
+ *
+ * PARCLogReporter *x_2 = parcLogReporterTextStdout_Acquire(x);
+ *
+ * parcLogReporterTextStdout_Release(&x);
+ * parcLogReporterTextStdout_Release(&x_2);
+ * }
+ * @endcode
+ */
+PARCLogReporter *parcLogReporterTextStdout_Acquire(const PARCLogReporter *instance);
+
+/**
+ * Release a previously acquired reference to the specified instance,
+ * decrementing the reference count for the instance.
+ *
+ * The pointer to the instance is set to NULL as a side-effect of this function.
+ *
+ * If the invocation causes the last reference to the instance to be released,
+ * the instance is deallocated and the instance's implementation will perform
+ * additional cleanup and release other privately held references.
+ *
+ * @param [in,out] reporterP A pointer to a PARCLogReporter instance pointer, which will be set to zero on return.
+ *
+ * Example:
+ * @code
+ * {
+ * PARCLogReporter *x = parcLogReporterTextStdout_Create();
+ *
+ * parcLogReporterTextStdout_Release(&x);
+ * }
+ * @endcode
+ */
+void parcLogReporterTextStdout_Release(PARCLogReporter **reporterP);
+
+/**
+ * Report the given PARCLogEntry
+ *
+ * @param [in] reporter A pointer to a valid PARCLogReporter instance.
+ * @param [in] entry A pointer to a valid PARCLogEntry instance.
+ *
+ * @see parcLogReporter_Report
+ */
+void parcLogReporterTextStdout_Report(PARCLogReporter *reporter, const PARCLogEntry *entry);
+
+#endif
diff --git a/libparc/parc/logging/test/.gitignore b/libparc/parc/logging/test/.gitignore
new file mode 100644
index 00000000..9b66ee0e
--- /dev/null
+++ b/libparc/parc/logging/test/.gitignore
@@ -0,0 +1,12 @@
+*.gcov
+*.gcda
+*.gcno
+*.log
+test_parc_LogEntry
+test_parc_Log
+test_parc_LogReporterFile
+test_parc_LogLevel
+test_parc_LogReporter
+test_parc_LogReporterTextStdout
+test_parc_LogFormatSyslog
+test_parc_LogFormatText
diff --git a/libparc/parc/logging/test/CMakeLists.txt b/libparc/parc/logging/test/CMakeLists.txt
new file mode 100644
index 00000000..060a0ba1
--- /dev/null
+++ b/libparc/parc/logging/test/CMakeLists.txt
@@ -0,0 +1,20 @@
+set(TestsExpectedToPass
+ test_parc_Log
+ test_parc_LogEntry
+ test_parc_LogFormatSyslog
+ test_parc_LogFormatText
+ test_parc_LogLevel
+ test_parc_LogReporter
+ test_parc_LogReporterFile
+ test_parc_LogReporterTextStdout
+ )
+
+# Enable gcov output for the tests
+add_definitions(--coverage)
+set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " --coverage")
+
+foreach(test ${TestsExpectedToPass})
+ AddTest(${test})
+endforeach()
+
+
diff --git a/libparc/parc/logging/test/test_parc_Log.c b/libparc/parc/logging/test/test_parc_Log.c
new file mode 100644
index 00000000..af9f65a5
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_Log.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+/** *
+ */
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Framework.
+#include "../parc_Log.c"
+
+#include <parc/logging/parc_LogLevel.h>
+#include <parc/logging/parc_LogReporterFile.h>
+
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/testing.h>
+#include <LongBow/debugging.h>
+
+LONGBOW_TEST_RUNNER(test_parc_Log)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified, but all tests should be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(CreateDestroy);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(test_parc_Log)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(test_parc_Log)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+uint32_t CreationInitialMemoryOutstanding = 0;
+
+LONGBOW_TEST_FIXTURE(CreateDestroy)
+{
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcLog_Create);
+ LONGBOW_RUN_TEST_CASE(CreateDestroy, parcLog_Create_DefaultValues);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(CreateDestroy)
+{
+ CreationInitialMemoryOutstanding = parcMemory_Outstanding();
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(CreateDestroy)
+{
+ if (parcMemory_Outstanding() != CreationInitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("'%s' leaks memory by %u\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - CreationInitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcLog_Create)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ parcOutputStream_Release(&output);
+
+ PARCLog *log = parcLog_Create("localhost", "test_parc_Log", NULL, reporter);
+ parcLogReporter_Release(&reporter);
+
+ assertTrue(parcLogLevel_Equals(parcLog_GetLevel(log), PARCLogLevel_Off), "Expected initial log level to be OFF");
+
+ parcLog_Release(&log);
+}
+
+LONGBOW_TEST_CASE(CreateDestroy, parcLog_Create_DefaultValues)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ parcOutputStream_Release(&output);
+
+ PARCLog *log = parcLog_Create(NULL, NULL, NULL, reporter);
+ parcLogReporter_Release(&reporter);
+
+ assertTrue(parcLogLevel_Equals(parcLog_GetLevel(log), PARCLogLevel_Off), "Expected initial log level to be OFF");
+
+ parcLog_Release(&log);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Emergency);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Warning);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Alert);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Critical);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Error);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Notice);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Debug);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Info);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Message);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_IsLoggable_True);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_IsLoggable_False);
+
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Emergency_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Warning_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Alert_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Critical_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Error_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Notice_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Debug_WrongLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLog_Info_WrongLevel);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ CreationInitialMemoryOutstanding = parcMemory_Outstanding();
+
+ {
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *output = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(output);
+ parcOutputStream_Release(&output);
+
+ PARCLog *log = parcLog_Create("localhost", "test_parc_Log", NULL, reporter);
+ parcLogReporter_Release(&reporter);
+
+ parcLog_SetLevel(log, PARCLogLevel_All);
+
+ longBowTestCase_SetClipBoardData(testCase, log);
+ }
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ {
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_Release(&log);
+ }
+
+ if (parcMemory_Outstanding() != CreationInitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("'%s' leaks memory by %u\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - CreationInitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_IsLoggable_True)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_IsLoggable(log, PARCLogLevel_Alert), "Expected parcLog_IsLoggable to be true.");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_IsLoggable_False)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_IsLoggable(log, PARCLogLevel_Alert), "Expected parcLog_IsLoggable to be true.");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Info)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Info(log, "This is a info message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Warning)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Warning(log, "This is a warning message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Emergency)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Emergency(log, "This is an emergency message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Alert)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Alert(log, "This is a alert message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Critical)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Critical(log, "This is a critical message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Notice)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Notice(log, "This is a notice message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Error)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Error(log, "This is a error message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Debug)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+
+ assertTrue(parcLog_Debug(log, "This is a debug message"),
+ "Expected message to be logged successfully");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Warning_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Warning(log, "This is a warning message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Emergency_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ // Even if the log level is set to off, you cannot block an emergency message.
+ assertTrue(parcLog_Emergency(log, "This is an emergency message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Alert_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Alert(log, "This is a finest message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Critical_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Critical(log, "This is a finer message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Notice_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Notice(log, "This is a fine message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Debug_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Debug(log, "This is a debug message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Error_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Error(log, "This is a debug message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Info_WrongLevel)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Off);
+
+ assertFalse(parcLog_Info(log, "This is a debug message"),
+ "Expected message to not be logged");
+}
+
+LONGBOW_TEST_CASE(Global, parcLog_Message)
+{
+ PARCLog *log = (PARCLog *) longBowTestCase_GetClipBoardData(testCase);
+ parcLog_SetLevel(log, PARCLogLevel_Alert);
+
+ assertTrue(parcLog_Message(log, PARCLogLevel_Alert, 0, "This is an alert message"),
+ "Expected message to be logged");
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(test_parc_Log);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogEntry.c b/libparc/parc/logging/test/test_parc_LogEntry.c
new file mode 100644
index 00000000..56a07c0d
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogEntry.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Runner.
+#include "../parc_LogEntry.c"
+
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+#include <pthread.h>
+
+#include <parc/algol/parc_Memory.h>
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/logging/parc_LogReporter.h>
+#include <parc/logging/parc_LogReporterTextStdout.h>
+#include <parc/logging/parc_LogFormatText.h>
+
+LONGBOW_TEST_RUNNER(parc_LogEntry)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Creation);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+
+ LONGBOW_RUN_TEST_FIXTURE(MultiThreaded);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_LogEntry)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_LogEntry)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Creation)
+{
+ LONGBOW_RUN_TEST_CASE(Creation, parcLogEntry_CreateRelease);
+}
+
+uint32_t CreationInitialMemoryOutstanding = 0;
+
+LONGBOW_TEST_FIXTURE_SETUP(Creation)
+{
+ CreationInitialMemoryOutstanding = parcMemory_Outstanding();
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Creation)
+{
+ if (parcMemory_Outstanding() != CreationInitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("'%s' leaks memory by %u\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - CreationInitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Creation, parcLogEntry_CreateRelease)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 12345, timeStamp, payload);
+ parcBuffer_Release(&payload);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLogEntry_Acquire, entry);
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetBuffer);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetTimeStamp);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetMessageId);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetApplicationName);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetHostName);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetLevel);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetProcessName);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogEntry_GetVersion);
+}
+
+uint32_t GlobalInitialMemoryOutstanding = 0;
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ GlobalInitialMemoryOutstanding = parcMemory_Outstanding();
+
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ if (parcMemory_Outstanding() != GlobalInitialMemoryOutstanding) {
+ parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("'%s' leaks memory by %u\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - GlobalInitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_AcquireRelease)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry = parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ parcBuffer_Release(&payload);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLogEntry_Acquire, entry);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetBuffer)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry = parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ PARCBuffer *actual = parcLogEntry_GetPayload(entry);
+
+ assertTrue(payload == actual, "Expected %p, actual %p", (void *) payload, (void *) actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetTimeStamp)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ const struct timeval *actual = parcLogEntry_GetTimeStamp(entry);
+
+ assertTrue(memcmp(&timeStamp, actual, sizeof(struct timeval)) == 0, "Expected timeStamp to be identical");
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetLevel)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ const PARCLogLevel actual = parcLogEntry_GetLevel(entry);
+
+ assertTrue(PARCLogLevel_Info == actual, "Expected %d, actual %d", PARCLogLevel_Info, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetVersion)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ const PARCLogLevel actual = parcLogEntry_GetVersion(entry);
+
+ assertTrue(_parcLog_Version == actual, "Expected %d, actual %d", _parcLog_Version, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetHostName)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ char *expected = "hostname";
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, expected, "applicationname", "processid", 1234, timeStamp, payload);
+ const char *actual = parcLogEntry_GetHostName(entry);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetApplicationName)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ char *expected = "applicationname";
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+ const char *actual = parcLogEntry_GetApplicationName(entry);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetProcessName)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ char *expected = "processid";
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", expected, 1234, timeStamp, payload);
+ const char *actual = parcLogEntry_GetProcessName(entry);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected %s, actual %s", expected, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_GetMessageId)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+
+ uint64_t expected = 1234;
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", expected, timeStamp, payload);
+ const uint64_t actual = parcLogEntry_GetMessageId(entry);
+
+ assertTrue(expected == actual, "Expected %" PRId64 " actual %" PRId64 "", expected, actual);
+ parcBuffer_Release(&payload);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogEntry_ToString)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ parcBuffer_Release(&payload);
+
+ char *actual = parcLogEntry_ToString(entry);
+
+ parcMemory_Deallocate((void **) &actual);
+
+ parcLogEntry_Release(&entry);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+ LONGBOW_RUN_TEST_CASE(Static, _parcLogEntry_Destroy);
+ LONGBOW_RUN_TEST_CASE(Static, _toString);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Static, _parcLogEntry_Destroy)
+{
+ testUnimplemented("");
+}
+
+LONGBOW_TEST_CASE(Static, _toString)
+{
+ testUnimplemented("");
+}
+
+// Multi-threaded test
+
+LONGBOW_TEST_FIXTURE(MultiThreaded)
+{
+ LONGBOW_RUN_TEST_CASE(MultiThreaded, fgThreadTest);
+ LONGBOW_RUN_TEST_CASE(MultiThreaded, bgThreadTest);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(MultiThreaded)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(MultiThreaded)
+{
+ if (parcSafeMemory_ReportAllocation(STDOUT_FILENO) != 0) {
+ //parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ printf("'%s' leaks memory by %u allocations\n",
+ longBowTestCase_GetName(testCase), parcMemory_Outstanding() - CreationInitialMemoryOutstanding);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+
+void *_runInThread(void *threadLabel);
+void *_runInThread_Stripped(void *threadLabel);
+
+static int _loopCount = INT32_MAX;
+
+void *
+_runInThread(void *threadLabel) // Look at _runInThread_Stripped(), below, instead of this one.
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+ PARCBuffer *payload = parcBuffer_AllocateCString(threadLabel);
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+
+ PARCLogEntry *entry = parcLogEntry_Create(PARCLogLevel_Info, "hostName", "applicationName", "processName", _loopCount, timeStamp, payload);
+
+ while (_loopCount > 0) {
+ PARCBuffer *buf = parcLogFormatText_FormatEntry(entry);
+
+ parcLogReporterTextStdout_Report(reporter, entry);
+ parcBuffer_Release(&buf);
+
+ _loopCount--;
+
+ usleep(10 * 1000); // yield for a bit to let another thread have at it.
+ }
+
+ parcLogEntry_Release(&entry);
+
+ parcBuffer_Release(&payload);
+ parcLogReporter_Release(&reporter);
+
+ return threadLabel; // Unchanged from what was passed in.
+}
+
+
+void *
+_runInThread_Stripped(void *threadLabel)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString(threadLabel);
+
+ while (_loopCount > 0) {
+ //
+ // The code below taken from parcLogReporterTextStdout_Report(). I stripped it down some.
+ // If you switch the thread's job from _runInThread_Stripped to _runInThread you can run
+ // the original, which shows the same thing.
+ //
+
+ PARCBufferComposer *composer = parcBufferComposer_Allocate(128);
+
+ parcBufferComposer_Format(composer, "%d [ ", _loopCount);
+ parcBufferComposer_PutBuffer(composer, payload);
+ parcBufferComposer_PutStrings(composer, " ]\n", NULL);
+
+ PARCBuffer *result = parcBuffer_Flip(parcBuffer_Acquire(parcBufferComposer_GetBuffer(composer)));
+ parcBufferComposer_Release(&composer);
+
+ char *string = parcBuffer_ToString(result);
+ parcBuffer_Release(&result);
+
+ printf("%s", string);
+
+ parcMemory_Deallocate((void **) &string);
+
+ _loopCount--;
+
+ usleep(10 * 1000); // yield for a bit to let another thread have at it.
+ }
+
+ parcBuffer_Release(&payload);
+
+ return threadLabel; // Unchanged from what was passed in.
+}
+
+
+LONGBOW_TEST_CASE(MultiThreaded, bgThreadTest)
+{
+ int numThreads = 2;
+ pthread_t workerThreads[numThreads];
+ char *threadLabel[numThreads];
+
+ _loopCount = INT32_MAX; // We'll set it to 0 after a second
+ for (int i = 0; i < numThreads; i++) {
+ if (asprintf(&threadLabel[i], "bg thread #%d", i) > 0) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_create(&workerThreads[i], &attr, _runInThread_Stripped, threadLabel[i]);
+ }
+ //pthread_create(&workerThreads[i], &attr, _runInThread, threadLabel[i]);
+ }
+
+ sleep(2); // Let the bg threads run
+
+ _loopCount = 0; // tell the bg threads to stop
+
+ for (int i = 0; i < numThreads; i++) {
+ int status = pthread_join(workerThreads[i], NULL);
+ printf("Child %d (out of %d) joined with status %d\n", i, numThreads, status);
+ free(threadLabel[i]);
+ }
+}
+
+LONGBOW_TEST_CASE(MultiThreaded, fgThreadTest)
+{
+ _loopCount = 10;
+ //_runInThread("main thread"); // Run the same logging loop, but in a single thread
+ _runInThread_Stripped("main thread"); // Run the same logging loop, but in a single thread
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_LogEntry);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogFormatSyslog.c b/libparc/parc/logging/test/test_parc_LogFormatSyslog.c
new file mode 100755
index 00000000..b5d1f4b5
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogFormatSyslog.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Runner.
+#include "../parc_LogFormatSyslog.c"
+
+#include <parc/logging/parc_LogEntry.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_LogFormatSyslog)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_LogFormatSyslog)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_LogFormatSyslog)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogFormatSyslog_FormatEntry);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogFormatSyslog_FormatEntry)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ PARCBuffer *actual = parcLogFormatSyslog_FormatEntry(entry);
+ assertTrue(parcBuffer_Remaining(actual) > 0, "Expected formatter to return non-zero length buffer");
+ parcLogEntry_Release(&entry);
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_LogFormatSyslog);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogFormatText.c b/libparc/parc/logging/test/test_parc_LogFormatText.c
new file mode 100644
index 00000000..0d294d36
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogFormatText.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Runner.
+#include "../parc_LogFormatText.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_LogFormatText)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_LogFormatText)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_LogFormatText)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogFormatText_FormatEntry);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogFormatText_FormatEntry)
+{
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ PARCBuffer *actual = parcLogFormatText_FormatEntry(entry);
+ assertTrue(parcBuffer_Remaining(actual) > 0, "Expected formatter to return non-zero length buffer");
+ parcLogEntry_Release(&entry);
+ parcBuffer_Release(&actual);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_LogFormatText);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogLevel.c b/libparc/parc/logging/test/test_parc_LogLevel.c
new file mode 100755
index 00000000..ca05cc5c
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogLevel.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Runner.
+#include "../parc_LogLevel.c"
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_LogLevel)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_LogLevel)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_LogLevel)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_Compare);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_Equals);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_ToString);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_ToString_All);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_ToString_Off);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_FromString_Debug);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogLevel_FromString_All);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_Compare)
+{
+ assertTrue(parcLogLevel_Compare(PARCLogLevel_Off, PARCLogLevel_All) < 0, "Expected PARCLogLevel_Off to be less that All");
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_Equals)
+{
+ assertTrue(parcLogLevel_Equals(PARCLogLevel_Emergency, PARCLogLevel_Emergency), "Expected equality");
+ assertFalse(parcLogLevel_Equals(PARCLogLevel_Emergency, PARCLogLevel_Debug), "Expected inequality");
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_ToString)
+{
+ char *expected = "Debug";
+ const char *actual = parcLogLevel_ToString(PARCLogLevel_Debug);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_ToString_Off)
+{
+ char *expected = "Off";
+ const char *actual = parcLogLevel_ToString(PARCLogLevel_Off);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_ToString_All)
+{
+ char *expected = "All";
+ const char *actual = parcLogLevel_ToString(PARCLogLevel_All);
+
+ assertTrue(strcmp(expected, actual) == 0, "Expected '%s', actual '%s'", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_FromString_Debug)
+{
+ PARCLogLevel expected = PARCLogLevel_Debug;
+ PARCLogLevel actual = parcLogLevel_FromString("DEBUG");
+
+ assertTrue(expected == actual, "Expected '%d', actual '%d'", expected, actual);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogLevel_FromString_All)
+{
+ PARCLogLevel expected = PARCLogLevel_All;
+ PARCLogLevel actual = parcLogLevel_FromString("AlL");
+
+ assertTrue(expected == actual, "Expected '%d', actual '%d'", expected, actual);
+}
+
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_LogLevel);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogReporter.c b/libparc/parc/logging/test/test_parc_LogReporter.c
new file mode 100644
index 00000000..5a9b0baa
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogReporter.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Runner.
+#include "../parc_LogReporter.c"
+
+#include <LongBow/unit-test.h>
+
+#include <stdio.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/logging/parc_LogReporterFile.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+LONGBOW_TEST_RUNNER(parc_LogReporter)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_LogReporter)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_LogReporter)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporter_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporter_Create_NULLObject);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporter_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporter_GetPrivateObject);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporter_Report);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporter_AcquireRelease)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLogReporter_Acquire, reporter);
+
+ parcOutputStream_Release(&out);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporter_Create)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+
+ parcOutputStream_Release(&out);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporter_Release(&reporter);
+}
+
+void
+testReporter(PARCLogReporter *reporter, const PARCLogEntry *entry)
+{
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporter_Create_NULLObject)
+{
+ PARCLogReporter *reporter = parcLogReporter_Create(NULL, NULL, testReporter, NULL);
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporter_GetPrivateObject)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+ parcOutputStream_Release(&out);
+
+ void *instance = parcLogReporter_GetPrivateObject(reporter);
+ assertNotNull(instance, "Expected the instance pointer to be non-NULL");
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporter_Report)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+ parcOutputStream_Release(&out);
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ parcLogReporter_Report(reporter, entry);
+ parcLogEntry_Release(&entry);
+ parcBuffer_Release(&payload);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporter_Release(&reporter);
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_LogReporter);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogReporterFile.c b/libparc/parc/logging/test/test_parc_LogReporterFile.c
new file mode 100755
index 00000000..9739c715
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogReporterFile.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Runner.
+#include "../parc_LogReporterFile.c"
+
+#include <parc/algol/parc_OutputStream.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_LogReporterFile)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_LogReporterFile)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_LogReporterFile)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporterFile_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporterFile_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parcLogReporterFile_Report);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporterFile_Create)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+ parcOutputStream_Release(&out);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporterFile_AcquireRelease)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLogReporterFile_Acquire, reporter);
+
+ parcOutputStream_Release(&out);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporterFile_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parcLogReporterFile_Report)
+{
+ PARCFileOutputStream *fileOutput = parcFileOutputStream_Create(dup(STDOUT_FILENO));
+ PARCOutputStream *out = parcFileOutputStream_AsOutputStream(fileOutput);
+ parcFileOutputStream_Release(&fileOutput);
+
+ PARCLogReporter *reporter = parcLogReporterFile_Create(out);
+ parcOutputStream_Release(&out);
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ parcLogReporter_Report(reporter, entry);
+ parcLogEntry_Release(&entry);
+ parcBuffer_Release(&payload);
+
+ assertNull(out, "Expected null value.");
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_LogReporterFile);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}
diff --git a/libparc/parc/logging/test/test_parc_LogReporterTextStdout.c b/libparc/parc/logging/test/test_parc_LogReporterTextStdout.c
new file mode 100755
index 00000000..004fbd58
--- /dev/null
+++ b/libparc/parc/logging/test/test_parc_LogReporterTextStdout.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * 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.
+ */
+
+
+// Include the file(s) containing the functions to be tested.
+// This permits internal static functions to be visible to this Test Runner.
+#include "../parc_LogReporterTextStdout.c"
+
+#include <stdio.h>
+
+#include <parc/algol/parc_OutputStream.h>
+#include <parc/algol/parc_FileOutputStream.h>
+#include <parc/testing/parc_ObjectTesting.h>
+
+#include <parc/algol/parc_SafeMemory.h>
+
+#include <LongBow/unit-test.h>
+
+LONGBOW_TEST_RUNNER(parc_LogReporterTextStdout)
+{
+ // The following Test Fixtures will run their corresponding Test Cases.
+ // Test Fixtures are run in the order specified here, but every test must be idempotent.
+ // Never rely on the execution order of tests or share state between them.
+ LONGBOW_RUN_TEST_FIXTURE(Global);
+ LONGBOW_RUN_TEST_FIXTURE(Static);
+}
+
+// The Test Runner calls this function once before any Test Fixtures are run.
+LONGBOW_TEST_RUNNER_SETUP(parc_LogReporterTextStdout)
+{
+ parcMemory_SetInterface(&PARCSafeMemoryAsPARCMemory);
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+// The Test Runner calls this function once after all the Test Fixtures are run.
+LONGBOW_TEST_RUNNER_TEARDOWN(parc_LogReporterTextStdout)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE(Global)
+{
+ LONGBOW_RUN_TEST_CASE(Global, parc_LogReporterTextStdout_AcquireRelease);
+ LONGBOW_RUN_TEST_CASE(Global, parc_LogReporterTextStdout_Create);
+ LONGBOW_RUN_TEST_CASE(Global, parc_LogReporterTextStdout_Report);
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Global)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Global)
+{
+ uint32_t outstandingAllocations = parcSafeMemory_ReportAllocation(STDOUT_FILENO);
+ if (outstandingAllocations != 0) {
+ printf("%s leaks %d memory allocations\n", longBowTestCase_GetName(testCase), outstandingAllocations);
+ return LONGBOW_STATUS_MEMORYLEAK;
+ }
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_CASE(Global, parc_LogReporterTextStdout_Create)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parc_LogReporterTextStdout_AcquireRelease)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+
+ parcObjectTesting_AssertAcquireReleaseContract(parcLogReporterTextStdout_Acquire, reporter);
+ parcLogReporterTextStdout_Release(&reporter);
+}
+
+LONGBOW_TEST_CASE(Global, parc_LogReporterTextStdout_Report)
+{
+ PARCLogReporter *reporter = parcLogReporterTextStdout_Create();
+
+ struct timeval timeStamp;
+ gettimeofday(&timeStamp, NULL);
+ PARCBuffer *payload = parcBuffer_AllocateCString("hello");
+ PARCLogEntry *entry =
+ parcLogEntry_Create(PARCLogLevel_Info, "hostname", "applicationname", "processid", 1234, timeStamp, payload);
+
+ parcLogReporter_Report(reporter, entry);
+ parcLogEntry_Release(&entry);
+ parcBuffer_Release(&payload);
+
+ parcLogReporter_Release(&reporter);
+}
+
+LONGBOW_TEST_FIXTURE(Static)
+{
+}
+
+LONGBOW_TEST_FIXTURE_SETUP(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+LONGBOW_TEST_FIXTURE_TEARDOWN(Static)
+{
+ return LONGBOW_STATUS_SUCCEEDED;
+}
+
+int
+main(int argc, char *argv[argc])
+{
+ LongBowRunner *testRunner = LONGBOW_TEST_RUNNER_CREATE(parc_LogReporterTextStdout);
+ int exitStatus = LONGBOW_TEST_MAIN(argc, argv, testRunner);
+ longBowTestRunner_Destroy(&testRunner);
+ exit(exitStatus);
+}