#ifndef __MESWEBLOG_H_
#define __MESWEBLOG_H_
#include <stdarg.h>
#include <stdio.h>
#define MES_INLINE inline
#define _MES_BEGIN_DECLS
#define _MES_END_DECLS
#define MES_FORMAT(x, y)
_MES_BEGIN_DECLS
typedef enum {
MES_LOGLEVEL_TRACE,
MES_LOGLEVEL_DEBUG,
MES_LOGLEVEL_INFO,
MES_LOGLEVEL_WARNING,
MES_LOGLEVEL_ERROR,
MES_LOGLEVEL_FATAL
} MES_LogLevel;
typedef enum {
MES_LOGCATEGORY_NETWORK,
MES_LOGCATEGORY_SECURECHANNEL,
MES_LOGCATEGORY_SESSION,
MES_LOGCATEGORY_SERVER,
MES_LOGCATEGORY_CLIENT,
MES_LOGCATEGORY_USERLAND,
MES_LOGCATEGORY_SECURITYPOLICY
} MES_LogCategory;
struct mytm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
};
typedef struct {
/* Log a message. The message string and following varargs are formatted
* according to the rules of the printf command. Use the convenience macros
* below that take the minimum log-level defined in ua_config.h into
* account. */
void (*log)(void* logContext, MES_LogLevel level, MES_LogCategory category,
const char* msg, va_list args);
void* context; /* Logger state */
void (*clear)(void* context); /* Clean up the logger plugin */
} MES_Logger;
static MES_INLINE MES_FORMAT(3, 4) void
MES_LOG_TRACE(const MES_Logger* logger, MES_LogCategory category, const char* msg, ...) {
#if MES_LOGLEVEL <= 100
if (!logger || !logger->log)
return;
va_list args; va_start(args, msg);
logger->log(logger->context, MES_LOGLEVEL_TRACE, category, msg, args);
va_end(args);
#else
(void)logger;
(void)category;
(void)msg;
#endif
}
static MES_INLINE MES_FORMAT(3, 4) void
MES_LOG_DEBUG(const MES_Logger* logger, MES_LogCategory category, const char* msg, ...) {
#if UA_LOGLEVEL <= 200
if (!logger || !logger->log)
return;
va_list args; va_start(args, msg);
logger->log(logger->context, MES_LOGLEVEL_DEBUG, category, msg, args);
va_end(args);
#else
(void)logger;
(void)category;
(void)msg;
#endif
}
static MES_INLINE MES_FORMAT(3, 4) void
MES_LOG_INFO(const MES_Logger* logger, MES_LogCategory category, const char* msg, ...) {
#if UA_LOGLEVEL <= 300
if (!logger || !logger->log)
return;
va_list args; va_start(args, msg);
logger->log(logger->context, MES_LOGLEVEL_INFO, category, msg, args);
va_end(args);
#else
(void)logger;
(void)category;
(void)msg;
#endif
}
static MES_INLINE MES_FORMAT(3, 4) void
MES_LOG_WARNING(const MES_Logger* logger, MES_LogCategory category, const char* msg, ...) {
#if MES_LOGLEVEL <= 400
if (!logger || !logger->log)
return;
va_list args; va_start(args, msg);
logger->log(logger->context, MES_LOGLEVEL_WARNING, category, msg, args);
va_end(args);
#else
(void)logger;
(void)category;
(void)msg;
#endif
}
static MES_INLINE MES_FORMAT(3, 4) void
MES_LOG_ERROR(const MES_Logger* logger, MES_LogCategory category, const char* msg, ...) {
#if MES_LOGLEVEL <= 500
if (!logger || !logger->log)
return;
va_list args; va_start(args, msg);
logger->log(logger->context, MES_LOGLEVEL_ERROR, category, msg, args);
va_end(args);
#else
(void)logger;
(void)category;
(void)msg;
#endif
}
static MES_INLINE MES_FORMAT(3, 4) void
MES_LOG_FATAL(const MES_Logger* logger, MES_LogCategory category, const char* msg, ...) {
#if MES_LOGLEVEL <= 600
if (!logger || !logger->log)
return;
va_list args; va_start(args, msg);
logger->log(logger->context, MES_LOGLEVEL_FATAL, category, msg, args);
va_end(args);
#else
(void)logger;
(void)category;
(void)msg;
#endif
}
_MES_END_DECLS
#include<limits.h>
/* 2000-03-01 (mod 400 year, immediately after feb29 */
#define LEAPOCH (946684800LL + 86400*(31+29))
#define DAYS_PER_400Y (365*400 + 97)
#define DAYS_PER_100Y (365*100 + 24)
#define DAYS_PER_4Y (365*4 + 1)
int __secs_to_tm(long long t, struct mytm* tm) {
long long days, secs, years;
int remdays, remsecs, remyears;
int qc_cycles, c_cycles, q_cycles;
int months;
static const char days_in_month[] = { 31,30,31,30,31,31,30,31,30,31,31,29 };
/* Reject time_t values whose year would overflow int */
if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL)
return -1;
secs = t - LEAPOCH;
days = secs / 86400LL;
remsecs = (int)(secs % 86400);
if (remsecs < 0) {
remsecs += 86400;
--days;
}
qc_cycles = (int)(days / DAYS_PER_400Y);
remdays = (int)(days % DAYS_PER_400Y);
if (remdays < 0) {
remdays += DAYS_PER_400Y;
--qc_cycles;
}
c_cycles = remdays / DAYS_PER_100Y;
if (c_cycles == 4) --c_cycles;
remdays -= c_cycles * DAYS_PER_100Y;
q_cycles = remdays / DAYS_PER_4Y;
if (q_cycles == 25) --q_cycles;
remdays -= q_cycles * DAYS_PER_4Y;
remyears = remdays / 365;
if (remyears == 4) --remyears;
remdays -= remyears * 365;
years = remyears + 4 * q_cycles + 100 * c_cycles + 400LL * qc_cycles;
for (months = 0; days_in_month[months] <= remdays; ++months)
remdays -= days_in_month[months];
if (years + 100 > INT_MAX || years + 100 < INT_MIN)
return -1;
tm->tm_year = (int)(years + 100);
tm->tm_mon = months + 2;
if (tm->tm_mon >= 12) {
tm->tm_mon -= 12;
++tm->tm_year;
}
tm->tm_mday = remdays + 1;
tm->tm_hour = remsecs / 3600;
tm->tm_min = remsecs / 60 % 60;
tm->tm_sec = remsecs % 60;
return 0;
}
#include <windows.h>
//#include <minwindef.h>
#include <time.h>
#include<string>
#include<iostream>
#include<fstream>
typedef unsigned __int16 uint16_t;
typedef uint16_t MES_UInt16;
typedef signed __int64 int64_t;
typedef int64_t MES_DateTime;
typedef int64_t MES_Int64;
#define ANSI_COLOR_RESET ""
#define MES_DATETIME_USEC 10LL
#define MES_MAXTIMEOUT 50
#define MES_DATETIME_MSEC (MES_DATETIME_USEC * 1000LL)
#define MES_DATETIME_SEC (MES_DATETIME_MSEC * 1000LL)
#define MES_DATETIME_UNIX_EPOCH (11644473600LL * MES_DATETIME_SEC)
#ifdef UA_ENABLE_LOG_COLORS
# define ANSI_COLOR_RED "\x1b[31m"
# define ANSI_COLOR_GREEN "\x1b[32m"
# define ANSI_COLOR_YELLOW "\x1b[33m"
# define ANSI_COLOR_BLUE "\x1b[34m"
# define ANSI_COLOR_MAGENTA "\x1b[35m"
# define ANSI_COLOR_CYAN "\x1b[36m"
# define ANSI_COLOR_RESET "\x1b[0m"
#else
# define ANSI_COLOR_RED ""
# define ANSI_COLOR_GREEN ""
# define ANSI_COLOR_YELLOW ""
# define ANSI_COLOR_BLUE ""
# define ANSI_COLOR_MAGENTA ""
# define ANSI_COLOR_CYAN ""
# define ANSI_COLOR_RESET ""
#endif
typedef struct MES_DateTimeStruct {
MES_UInt16 nanoSec;
MES_UInt16 microSec;
MES_UInt16 milliSec;
MES_UInt16 sec;
MES_UInt16 min;
MES_UInt16 hour;
MES_UInt16 day; /* From 1 to 31 */
MES_UInt16 month; /* From 1 to 12 */
MES_UInt16 year;
} MES_DateTimeStruct;
const char* logLevelNames[6] = { "trace", "debug",
ANSI_COLOR_GREEN "info",
ANSI_COLOR_YELLOW "warn",
ANSI_COLOR_RED "error",
ANSI_COLOR_MAGENTA "fatal" };
const char* logCategoryNames[7] = { "network", "channel", "session", "server",
"client", "userland", "securitypolicy" };
const char* logMesFunction[] = {"DeviceStatus", "Alarm", "Product",
"Process", "Orders", "PersonCheck",
"MaterialCheck", "DeviceStartUpCheck"};
MES_DateTime MES_DateTime_now(void)
{
/* Windows filetime has the same definition as UA_DateTime */
FILETIME ft;
SYSTEMTIME st;
GetSystemTime(&st);
SystemTimeToFileTime(&st, &ft);
ULARGE_INTEGER ul;
ul.LowPart = ft.dwLowDateTime;
ul.HighPart = ft.dwHighDateTime;
return (MES_DateTime)ul.QuadPart;
}
MES_Int64 MES_DateTime_localTimeUtcOffset(void) {
time_t gmt, rawtime = time(NULL);
struct tm ptm;
gmtime_s(&ptm, &rawtime);
// Request that mktime() looksup dst in timezone database
ptm.tm_isdst = -1;
gmt = mktime(&ptm);
return (MES_Int64)(difftime(rawtime, gmt) * MES_DATETIME_SEC);
}
MES_DateTimeStruct MES_DateTime_toStruct(MES_DateTime t)
{
/* Calculating the the milli-, micro- and nanoseconds */
MES_DateTimeStruct dateTimeStruct;
if (t >= 0) {
dateTimeStruct.nanoSec = (MES_UInt16)((t % 10) * 100);
dateTimeStruct.microSec = (MES_UInt16)((t % 10000) / 10);
dateTimeStruct.milliSec = (MES_UInt16)((t % 10000000) / 10000);
}
else {
dateTimeStruct.nanoSec = (MES_UInt16)(((t % 10 + t) % 10) * 100);
dateTimeStruct.microSec = (MES_UInt16)(((t % 10000 + t) % 10000) / 10);
dateTimeStruct.milliSec = (MES_UInt16)(((t % 10000000 + t) % 10000000) / 10000);
}
/* Calculating the unix time with #include <time.h> */
long long secSinceUnixEpoch = (long long)(t / MES_DATETIME_SEC)
- (long long)(MES_DATETIME_UNIX_EPOCH / MES_DATETIME_SEC);
struct mytm ts;
memset(&ts, 0, sizeof(struct mytm));
__secs_to_tm(secSinceUnixEpoch, &ts);
dateTimeStruct.sec = (MES_UInt16)ts.tm_sec;
dateTimeStruct.min = (MES_UInt16)ts.tm_min;
dateTimeStruct.hour = (MES_UInt16)ts.tm_hour;
dateTimeStruct.day = (MES_UInt16)ts.tm_mday;
dateTimeStruct.month = (MES_UInt16)(ts.tm_mon + 1);
dateTimeStruct.year = (MES_UInt16)(ts.tm_year + 1900);
return dateTimeStruct;
}
void UA_Log_Print(MES_Int64 tOffset, MES_DateTimeStruct dts, MES_LogLevel level, MES_LogCategory category, std::string szLogMess)
{
char szLogMsg[512] = { 0 };
char szLogFileName[64] = { 0 };
sprintf(szLogMsg, "[%04u-%02u-%02u %02u:%02u:%02u.%03u (UTC%+05d)] %s/%s" ANSI_COLOR_RESET "\t", dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.milliSec,
(int)(tOffset / MES_DATETIME_SEC / 36), logLevelNames[level], logCategoryNames[category]);
sprintf(szLogFileName, "%04u%02u%uKingViewMes.log", dts.year, dts.month, dts.day);
std::string szLogTime(szLogMsg);
std::string strLogFileName(szLogFileName);
std::fstream m_FsFile;
m_FsFile.open(strLogFileName, std::ios::app | std::ios::out | std::ios::in);
m_FsFile << szLogTime << szLogMess << std::endl;
m_FsFile.close();
}
inline void MES_Log_Stdout_log(void* context, MES_LogLevel level, MES_LogCategory category,
const char* msg, va_list args) {
/* Assume that context is casted to UA_LogLevel */
/* TODO we may later change this to a struct with bitfields to filter on category */
if (context != NULL && (MES_LogLevel)(uintptr_t)context > level)
return;
MES_Int64 tOffset = MES_DateTime_localTimeUtcOffset();
MES_DateTimeStruct dts = MES_DateTime_toStruct(MES_DateTime_now() + tOffset);
#if MES_MULTITHREADING >= 200
pthread_mutex_lock(&printf_mutex);
#endif
printf("[%04u-%02u-%02u %02u:%02u:%02u.%03u (UTC%+05d)] %s/%s" ANSI_COLOR_RESET "\t",
dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.milliSec,
(int)(tOffset / MES_DATETIME_SEC / 36), logLevelNames[level], logCategoryNames[category]);
vprintf(msg, args);
char szLogMsg[512] = { 0 };
vsprintf(szLogMsg, msg, args);
#ifdef UA_ENABLE_MES
UA_Log_Print(tOffset, dts, level, category, szLogMsg);
#endif
printf("\n");
fflush(stdout);
#if UA_MULTITHREADING >= 200
pthread_mutex_unlock(&printf_mutex);
#endif
}
inline void MES_Log_Stdout_clear(void* logContext)
{
}
const MES_Logger MES_Log_Stdout_ = { MES_Log_Stdout_log, NULL, MES_Log_Stdout_clear };
const MES_Logger* MES_Log_Stdout = &MES_Log_Stdout_;
/* By default the client and server is configured with UA_Log_Stdout
This constructs a logger with a configurable max log level */
MES_Logger UA_Log_Stdout_withLevel(MES_LogLevel minlevel)
{
MES_Logger logger = { MES_Log_Stdout_log, (void*)minlevel, MES_Log_Stdout_clear };
return logger;
}
#endif
/* MES_Int64 tOffset = MES_DateTime_localTimeUtcOffset();
MES_DateTimeStruct dts = MES_DateTime_toStruct(MES_DateTime_now() + tOffset);
MES_LOG_INFO(MES_Log_Stdout, MES_LOGCATEGORY_USERLAND, "date is: %u-%u-%u %u:%u:%u.%03u\n",
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);*/
MES_LOG_INFO(MES_Log_Stdout, MES_LOGCATEGORY_NETWORK, "Reconnect to server is %d | The response is %s.", nRet, szResponse.c_str());