diff options
Diffstat (limited to 'libparc/parc/logging')
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); +} |