/** * @file mprLog.c * @brief Mbedthis Portable Runtime (MPR) Logging and error reporting. * @remarks We always provide these routines. */ /*********************************** License **********************************/ /* * @copy default * * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved. * * This software is distributed under commercial and open source licenses. * You may use the GPL open source license described below or you may acquire * a commercial license from Mbedthis Software. You agree to be fully bound * by the terms of either license. Consult the LICENSE.TXT distributed with * this software for full details. * * This software is open source; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See the GNU General Public License for more * details at: http://www.mbedthis.com/downloads/gplLicense.html * * This program is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * This GPL license does NOT permit incorporating this software into * proprietary programs. If you are unable to comply with the GPL, you must * acquire a commercial license to use this software. Commercial licenses * for this software and support services are available from Mbedthis * Software at http://www.mbedthis.com * * @end */ #include "mpr.h" /****************************** Forward Declarations **************************/ static void defaultLogHandler(MPR_LOC_DEC(ctx, loc), int flags, int level, const char *msg); static void logOutput(MPR_LOC_DEC(ctx, loc), int flags, int level, const char *msg); /************************************ Code ************************************/ void mprLog(MprCtx ctx, int level, const char *fmt, ...) { va_list args; char *buf; if (level > mprGetLogLevel(ctx)) { return; } va_start(args, fmt); mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args); va_end(args); logOutput(MPR_LOC_ARGS(ctx), MPR_LOG_SRC, level, buf); va_end(args); mprFree(buf); } /*****************************************************************************/ /* * Do raw output */ void mprRawLog(MprCtx ctx, const char *fmt, ...) { va_list args; char *buf; int len; va_start(args, fmt); len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args); va_end(args); logOutput(MPR_LOC_ARGS(ctx), MPR_RAW, 0, buf); mprFree(buf); } /*****************************************************************************/ /* * Handle an error */ void mprError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...) { va_list args; char *buf; int len; va_start(args, fmt); len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args); va_end(args); logOutput(MPR_LOC_PASS(ctx, loc), MPR_ERROR_MSG | MPR_ERROR_SRC, 0, buf); mprFree(buf); } /*****************************************************************************/ /* * Handle an error that should be displayed to the user */ void mprUserError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...) { va_list args; char *buf; int len; va_start(args, fmt); len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args); va_end(args); logOutput(MPR_LOC_PASS(ctx, loc), MPR_USER_MSG | MPR_ERROR_SRC, 0, buf); mprFree(buf); } /*****************************************************************************/ /* * Handle a fatal error. Forcibly shutdown the application. */ void mprFatalError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...) { va_list args; char *buf; int len; va_start(args, fmt); len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args); va_end(args); logOutput(MPR_LOC_PASS(ctx, loc), MPR_USER_MSG | MPR_FATAL_SRC, 0, buf); mprFree(buf); #if BREW mprSignalExit(ctx); #else exit(2); #endif } /*****************************************************************************/ /* * Handle a program assertion */ void mprAssertError(MPR_LOC_DEC(ctx, loc), const char *msg) { logOutput(MPR_LOC_PASS(ctx, loc), MPR_ASSERT_MSG | MPR_ASSERT_SRC, 0, msg); } /*****************************************************************************/ /* * Handle an error */ void mprStaticError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...) { va_list args; int len; char buf[MPR_MAX_STRING]; va_start(args, fmt); len = mprVsprintf(buf, sizeof(buf), fmt, args); va_end(args); logOutput(MPR_LOC_PASS(ctx, loc), MPR_ERROR_MSG | MPR_ERROR_SRC, 0, buf); } /*****************************************************************************/ /* * Direct output to the standard output. Does not hook into the logging * system and does not allocate memory. */ void mprStaticAssert(const char *loc, const char *msg) { #if BLD_DEBUG char buf[MPR_MAX_STRING]; int len; len = mprSprintf(buf, sizeof(buf), "Assertion %s, failed at %s\n", msg, loc); mprBreakpoint(loc, buf); #if BLD_HOST_UNIX /* * MOB -- but is stdout always okay to use */ write(1, buf, len); #elif BREW || WIN /* * Only time we use printf. We can't get an alloc context so we have * to use real print */ #if BREW && !BREW_SIMULATOR printf(" MP: %s\n", buf); #else printf("%s\n", buf); #endif #endif #endif } /*****************************************************************************/ int mprGetLogLevel(MprCtx ctx) { return mprGetApp(ctx)->logLevel; } /******************************************************************************/ void mprSetLogLevel(MprCtx ctx, int level) { mprGetApp(ctx)->logLevel = level; } /*****************************************************************************/ /* * Output a log message to the log handler */ static void logOutput(MPR_LOC_DEC(ctx, loc), int flags, int level, const char *msg) { MprLogHandler handler; if (flags & (MPR_ERROR_SRC | MPR_FATAL_SRC | MPR_ASSERT_SRC)) { mprBreakpoint(MPR_LOC, 0); } mprAssert(ctx != 0); handler = mprGetApp(ctx)->logHandler; if (handler != 0) { (handler)(MPR_LOC_PASS(ctx, loc), flags, level, msg); return; } defaultLogHandler(MPR_LOC_PASS(ctx, loc), flags, level, msg); } /*****************************************************************************/ /* * Default log output is just to the console */ static void defaultLogHandler(MPR_LOC_DEC(ctx, loc), int flags, int level, const char *msg) { MprApp *app; char *prefix; app = mprGetApp(ctx); prefix = app->name; while (*msg == '\n') { mprPrintf(ctx, "\n"); msg++; } if (flags & MPR_LOG_SRC) { #if BREW && !BREW_SIMULATOR mprPrintf(ctx, "%s\n", msg); #else mprPrintf(ctx, "%s: %d: %s\n", prefix, level, msg); #endif } else if (flags & MPR_ERROR_SRC) { /* * Use static printing to avoid malloc when the messages are small. * This is important for memory allocation errors. */ if (strlen(msg) < (MPR_MAX_STRING - 32)) { mprStaticPrintf(ctx, "%s: Error: %s\n", prefix, msg); } else { mprPrintf(ctx, "%s: Error: %s\n", prefix, msg); } } else if (flags & MPR_FATAL_SRC) { mprPrintf(ctx, "%s: Fatal: %s\n", prefix, msg); } else if (flags & MPR_ASSERT_SRC) { #if BLD_FEATURE_ALLOC_LEAK_TRACK mprPrintf(ctx, "%s: Assertion %s, failed at %s\n", prefix, msg, loc); #else mprPrintf(ctx, "%s: Assertion %s, failed\n", prefix, msg); #endif } else if (flags & MPR_RAW) { mprPrintf(ctx, "%s", msg); } else { return; } } /*****************************************************************************/ /* * Map the O/S error code to portable error codes. */ int mprGetOsError() { #if WIN int rc; rc = GetLastError(); /* * Client has closed the pipe */ if (rc == ERROR_NO_DATA) { return EPIPE; } return rc; #endif #if LINUX || VXWORKS || SOLARIS return errno; #endif #if BREW /* * No such thing on Brew. Errors are per class */ return 0; #endif } /******************************************************************************/ #if UNUSED const char *mprGetErrorMsg(int err) { /* * MPR error messages. Declare here so we don't have any globals. */ char *mprErrMessages[] = { /* 0 MPR_ERR_OK */ "Success", /* -201 MPR_ERR_GENERAL */ "General error", /* -202 MPR_ERR_ABORTED */ "Aborted", /* -203 MPR_ERR_ALREADY_EXISTS */ "Already exists", /* -204 MPR_ERR_BAD_ARGS */ "Bad args", /* -205 MPR_ERR_BAD_FORMAT */ "Bad format", /* -206 MPR_ERR_BAD_HANDLE */ "Bad handle", /* -207 MPR_ERR_BAD_STATE */ "Bad state", /* -208 MPR_ERR_BAD_SYNTAX */ "Bad syntax", /* -209 MPR_ERR_BAD_TYPE */ "Bad type", /* -210 MPR_ERR_BAD_VALUE */ "Bad value", /* -211 MPR_ERR_BUSY */ "Busy", /* -212 MPR_ERR_CANT_ACCESS */ "Can't access", /* -213 MPR_ERR_CANT_COMPLETE */ "Can't complete", /* -214 MPR_ERR_CANT_CREATE */ "Can't create", /* -215 MPR_ERR_CANT_INITIALIZE */ "Can't initialize", /* -216 MPR_ERR_CANT_OPEN */ "Can't open", /* -217 MPR_ERR_CANT_READ */ "Can't read", /* -218 MPR_ERR_CANT_WRITE */ "Can't write", /* -219 MPR_ERR_DELETED */ "Already deleted", /* -220 MPR_ERR_NETWORK */ "Network error", /* -221 MPR_ERR_NOT_FOUND */ "Not found", /* -222 MPR_ERR_NOT_INITIALIZED */ "Not initialized", /* -223 MPR_ERR_NOT_READY */ "Not ready", /* -224 MPR_ERR_READ_ONLY */ "Read only", /* -225 MPR_ERR_TIMEOUT */ "Timeout", /* -226 MPR_ERR_TOO_MANY */ "Too many", /* -227 MPR_ERR_WONT_FIT */ "Won't fit", /* -228 MPR_ERR_WOULD_BLOCK */ "Would block", /* -229 MPR_ERR_CANT_ALLOCATE */ "Can't allocate", }; int mprNumErr = sizeof(mprErrMessages) / sizeof(char*); /* * Operating system error messages */ #if WIN char *osErrMessages[] = { /* 0 */ "No error", /* 1 EPERM */ "Operation not permitted", /* 2 ENOENT */ "No such file or directory", /* 3 ESRCH */ "No such process", /* 4 EINTR */ "Interrupted function call", /* 5 EIO */ "I/O error", /* 6 ENXIO */ "No such device or address", /* 7 E2BIG */ "Arg list too long", /* 8 ENOEXEC */ "Exec format error", /* 9 EBADF */ "Bad file number", /* 10 ECHILD */ "No child processes", /* 11 EAGAIN */ "Try again", /* 12 ENOMEM */ "Out of memory", /* 13 EACCES */ "Permission denied", /* 14 EFAULT */ "Bad address", /* 15 ENOTBLK */ "Unknown error", /* 16 EBUSY */ "Resource busy", /* 17 EEXIST */ "File exists", /* 18 EXDEV */ "Improper link", /* 19 ENODEV */ "No such device", /* 20 ENOTDIR */ "Not a directory", /* 21 EISDIR */ "Is a directory", /* 22 EINVAL */ "Invalid argument", /* 23 ENFILE */ "Too many open files in system", /* 24 EMFILE */ "Too many open files", /* 25 ENOTTY */ "Inappropriate I/O control operation", /* 26 ETXTBSY */ "Unknown error", /* 27 EFBIG */ "File too large", /* 28 ENOSPC */ "No space left on device", /* 29 ESPIPE */ "Invalid seek", /* 30 EROFS */ "Read-only file system", /* 31 EMLINK */ "Too many links", /* 32 EPIPE */ "Broken pipe", /* 33 EDOM */ "Domain error", /* 34 ERANGE */ "Result too large", /* 35 EUCLEAN */ "Unknown error", /* 36 EDEADLK */ "Resource deadlock would occur", /* 37 UNKNOWN */ "Unknown error", /* 38 ENAMETOOLONG */ "Filename too long", /* 39 ENOLCK */ "No locks available", /* 40 ENOSYS */ "Function not implemented", /* 41 ENOTEMPTY */ "Directory not empty", /* 42 EILSEQ */ "Illegal byte sequence", /* 43 ENETDOWN */ "Network is down", /* 44 ECONNRESET */ "Connection reset", /* 45 ECONNREFUSED */ "Connection refused", /* 46 EADDRINUSE */ "Address already in use" }; #else /* WIN */ char *osErrMessages[] = { /* 0 */ "Success" /* 1 EPERM */ "Operation not permitted" /* 2 ENOENT */ "No such file or directory" /* 3 ESRCH */ "No such process" /* 4 EINTR */ "Interrupted system call" /* 5 EIO */ "I/O error" /* 6 ENXIO */ "No such device or address" /* 7 E2BIG */ "Arg list too long" /* 8 ENOEXEC */ "Exec format error" /* 9 EBADF */ "Bad file number" /* 10 ECHILD */ "No child processes" /* 11 EAGAIN */ "Try again" /* 12 ENOMEM */ "Out of memory" /* 13 EACCES */ "Permission denied" /* 14 EFAULT */ "Bad address" /* 15 ENOTBLK */ "Block device required" /* 16 EBUSY */ "Device or resource busy" /* 17 EEXIST */ "File exists" /* 18 EXDEV */ "Cross-device link" /* 19 ENODEV */ "No such device" /* 20 ENOTDIR */ "Not a directory" /* 21 EISDIR */ "Is a directory" /* 22 EINVAL */ "Invalid argument" /* 23 ENFILE */ "File table overflow" /* 24 EMFILE */ "Too many open files" /* 25 ENOTTY */ "Not a typewriter" /* 26 ETXTBSY */ "Text file busy" /* 27 EFBIG */ "File too large" /* 28 ENOSPC */ "No space left on device" /* 29 ESPIPE */ "Illegal seek" /* 30 EROFS */ "Read-only file system" /* 31 EMLINK */ "Too many links" /* 32 EPIPE */ "Broken pipe" /* 33 EDOM */ "Math argument out of domain of func" /* 34 ERANGE */ "Math result not representable" /* 35 EDEADLK */ "Resource deadlock would occur" /* 36 ENAMETOOLONG */ "File name too long" /* 37 ENOLCK */ "No record locks available" /* 38 ENOSYS */ "Function not implemented" /* 39 ENOTEMPTY */ "Directory not empty" /* 40 ELOOP */ "Too many symbolic links encountered" /* 41 EWOULDBLOCK EAGAIN */"Operation would block" /* 42 ENOMSG */ "No message of desired type" /* 43 EIDRM */ "Identifier removed" #if !BLD_FEATURE_SQUEEZE /* 44 ECHRNG */ "Channel number out of range" /* 45 EL2NSYNC */ "Level 2 not synchronized" /* 46 EL3HLT */ "Level 3 halted" /* 47 EL3RST */ "Level 3 reset" /* 48 ELNRNG */ "Link number out of range" /* 49 EUNATCH */ "Protocol driver not attached" /* 50 ENOCSI */ "No CSI structure available" /* 51 EL2HLT */ "Level 2 halted" /* 52 EBADE */ "Invalid exchange" /* 53 EBADR */ "Invalid request descriptor" /* 54 EXFULL */ "Exchange full" /* 55 ENOANO */ "No anode" /* 56 EBADRQC */ "Invalid request code" /* 57 EBADSLT */ "Invalid slot" /* 59 EBFONT */ "Bad font file format" /* 60 ENOSTR */ "Device not a stream" /* 61 ENODATA */ "No data available" /* 62 ETIME */ "Timer expired" /* 63 ENOSR */ "Out of streams resources" /* 64 ENONET */ "Machine is not on the network" /* 65 ENOPKG */ "Package not installed" /* 66 EREMOTE */ "Object is remote" /* 67 ENOLINK */ "Link has been severed" /* 68 EADV */ "Advertise error" /* 69 ESRMNT */ "Srmount error" /* 70 ECOMM */ "Communication error on send" /* 71 EPROTO */ "Protocol error" /* 72 EMULTIHOP */ "Multihop attempted" /* 73 EDOTDOT */ "RFS specific error" /* 74 EBADMSG */ "Not a data message" /* 75 EOVERFLOW */ "Value too large for defined data type" /* 76 ENOTUNIQ */ "Name not unique on network" /* 77 EBADFD */ "File descriptor in bad state" /* 78 EREMCHG */ "Remote address changed" /* 79 ELIBACC */ "Can not access a needed shared library" /* 80 ELIBBAD */ "Accessing a corrupted shared library" /* 81 ELIBSCN */ ".lib section in a.out corrupted" /* 82 ELIBMAX */ "Linking in too many shared libraries" /* 83 ELIBEXEC */ "Cannot exec a shared library directly" /* 84 EILSEQ */ "Illegal byte sequence" /* 85 ERESTART */ "Interrupted system call should be restarted" /* 86 ESTRPIPE */ "Streams pipe error" /* 87 EUSERS */ "Too many users" /* 88 ENOTSOCK */ "Socket operation on non-socket" /* 89 EDESTADDRREQ */ "Destination address required" /* 90 EMSGSIZE */ "Message too long" /* 91 EPROTOTYPE */ "Protocol wrong type for socket" /* 92 ENOPROTOOPT */ "Protocol not available" /* 93 EPROTONOSUPPORT */ "Protocol not supported" /* 94 ESOCKTNOSUPPORT */ "Socket type not supported" /* 95 EOPNOTSUPP */ "Operation not supported on transport endpoint" /* 96 EPFNOSUPPORT */ "Protocol family not supported" /* 97 EAFNOSUPPORT */ "Address family not supported by protocol" /* 98 EADDRINUSE */ "Address already in use" /* 99 EADDRNOTAVAIL */ "Cannot assign requested address" /* 100 ENETDOWN */ "Network is down" /* 101 ENETUNREACH */ "Network is unreachable" /* 102 ENETRESET */ "Network dropped connection because of reset" /* 103 ECONNABORTED */ "Software caused connection abort" /* 104 ECONNRESET */ "Connection reset by peer" /* 105 ENOBUFS */ "No buffer space available" /* 106 EISCONN */ "Transport endpoint is already connected" /* 107 ENOTCONN */ "Transport endpoint is not connected" /* 108 ESHUTDOWN */ "Cannot send after transport endpoint shutdown" /* 109 ETOOMANYREFS */ "Too many references: cannot splice" /* 110 ETIMEDOUT */ "Connection timed out" /* 111 ECONNREFUSED */ "Connection refused" /* 112 EHOSTDOWN */ "Host is down" /* 113 EHOSTUNREACH */ "No route to host" /* 114 EALREADY */ "Operation already in progress" /* 115 EINPROGRESS */ "Operation now in progress" /* 116 ESTALE */ "Stale NFS file handle" /* 117 EUCLEAN */ "Structure needs cleaning" /* 118 ENOTNAM */ "Not a XENIX named type file" /* 119 ENAVAIL */ "No XENIX semaphores available" /* 120 EISNAM */ "Is a named type file" /* 121 EREMOTEIO */ "Remote I/O error" /* 122 EDQUOT */ "Quota exceeded" /* 123 ENOMEDIUM */ "No medium found" /* 124 EMEDIUMTYPE */ "Wrong medium type" }; #endif /* BLD_FEATURE_SQUEEZE */ #endif /* WIN */ int osNumErr = sizeof(osErrMessages) / sizeof(char*); if (err < MPR_ERR_BASE) { err = MPR_ERR_BASE - err; if (err < 0 || err >= mprNumErr) { return "Bad error code"; } return mprErrMessages[err]; } else { /* * Negative O/S error code. Map to a positive standard Posix error. */ err = -err; if (err < 0 || err >= osNumErr) { return "Bad O/S error code"; } return osErrMessages[err]; } } #endif /*****************************************************************************/ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim:tw=78 * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */