Write to the Windows eventlog in UTF16, converting the message encoding

as necessary.

Itagaki Takahiro with some changes from me
This commit is contained in:
Magnus Hagander 2009-10-17 00:24:51 +00:00
parent 76c09dbe8d
commit 748771379b
4 changed files with 214 additions and 146 deletions

View File

@ -42,7 +42,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.217 2009/07/03 19:14:25 petere Exp $
* $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.218 2009/10/17 00:24:50 mha Exp $
*
*-------------------------------------------------------------------------
*/
@ -111,8 +111,10 @@ static int syslog_facility = LOG_LOCAL0;
static void write_syslog(int level, const char *line);
#endif
static void write_console(const char *line, int len);
#ifdef WIN32
static void write_eventlog(int level, const char *line);
static void write_eventlog(int level, const char *line, int len);
#endif
/* We provide a small stack of ErrorData records for re-entrant cases */
@ -1567,10 +1569,11 @@ write_syslog(int level, const char *line)
* Write a message line to the windows event log
*/
static void
write_eventlog(int level, const char *line)
write_eventlog(int level, const char *line, int len)
{
int eventlevel = EVENTLOG_ERROR_TYPE;
static HANDLE evtHandle = INVALID_HANDLE_VALUE;
WCHAR *utf16;
int eventlevel = EVENTLOG_ERROR_TYPE;
static HANDLE evtHandle = INVALID_HANDLE_VALUE;
if (evtHandle == INVALID_HANDLE_VALUE)
{
@ -1606,8 +1609,34 @@ write_eventlog(int level, const char *line)
break;
}
/*
* Convert message to UTF16 text and write it with ReportEventW,
* but fall-back into ReportEventA if conversion failed.
*
* Also verify that we are not on our way into error recursion trouble
* due to error messages thrown deep inside pgwin32_toUTF16().
*/
if (GetDatabaseEncoding() != GetPlatformEncoding() &&
!in_error_recursion_trouble())
{
utf16 = pgwin32_toUTF16(line, len, NULL);
if (utf16)
{
ReportEventW(evtHandle,
eventlevel,
0,
0, /* All events are Id 0 */
NULL,
1,
0,
(LPCWSTR *) &utf16,
NULL);
ReportEvent(evtHandle,
pfree(utf16);
return;
}
}
ReportEventA(evtHandle,
eventlevel,
0,
0, /* All events are Id 0 */
@ -1619,6 +1648,52 @@ write_eventlog(int level, const char *line)
}
#endif /* WIN32 */
static void
write_console(const char *line, int len)
{
#ifdef WIN32
/*
* WriteConsoleW() will fail of stdout is redirected, so just fall through
* to writing unconverted to the logfile in this case.
*/
if (GetDatabaseEncoding() != GetPlatformEncoding() &&
!in_error_recursion_trouble() &&
!redirection_done)
{
WCHAR *utf16;
int utf16len;
utf16 = pgwin32_toUTF16(line, len, &utf16len);
if (utf16 != NULL)
{
HANDLE stdHandle;
DWORD written;
stdHandle = GetStdHandle(STD_ERROR_HANDLE);
if (WriteConsoleW(stdHandle, utf16, utf16len, &written, NULL))
{
pfree(utf16);
return;
}
/*
* In case WriteConsoleW() failed, fall back to writing the message
* unconverted.
*/
pfree(utf16);
}
}
#else
/*
* Conversion on non-win32 platform is not implemented yet.
* It requires non-throw version of pg_do_encoding_conversion(),
* that converts unconvertable characters to '?' without errors.
*/
#endif
write(fileno(stderr), line, len);
}
/*
* setup formatted_log_time, for consistent times between CSV and regular logs
*/
@ -2206,7 +2281,7 @@ send_message_to_server_log(ErrorData *edata)
/* Write to eventlog, if enabled */
if (Log_destination & LOG_DESTINATION_EVENTLOG)
{
write_eventlog(edata->elevel, buf.data);
write_eventlog(edata->elevel, buf.data, buf.len);
}
#endif /* WIN32 */
@ -2230,10 +2305,10 @@ send_message_to_server_log(ErrorData *edata)
* because that's really a pipe to the syslogger process.
*/
else if (pgwin32_is_service())
write_eventlog(edata->elevel, buf.data);
write_eventlog(edata->elevel, buf.data, buf.len);
#endif
else
write(fileno(stderr), buf.data, buf.len);
write_console(buf.data, buf.len);
}
/* If in the syslogger process, try to write messages direct to file */
@ -2256,12 +2331,12 @@ send_message_to_server_log(ErrorData *edata)
{
const char *msg = _("Not safe to send CSV data\n");
write(fileno(stderr), msg, strlen(msg));
write_console(msg, strlen(msg));
if (!(Log_destination & LOG_DESTINATION_STDERR) &&
whereToSendOutput != DestDebug)
{
/* write message to stderr unless we just sent it above */
write(fileno(stderr), buf.data, buf.len);
write_console(buf.data, buf.len);
}
pfree(buf.data);
}
@ -2642,6 +2717,9 @@ void
write_stderr(const char *fmt,...)
{
va_list ap;
#ifdef WIN32
char errbuf[2048]; /* Arbitrary size? */
#endif
fmt = _(fmt);
@ -2651,6 +2729,7 @@ write_stderr(const char *fmt,...)
vfprintf(stderr, fmt, ap);
fflush(stderr);
#else
vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
/*
* On Win32, we print to stderr if running on a console, or write to
@ -2658,16 +2737,12 @@ write_stderr(const char *fmt,...)
*/
if (pgwin32_is_service()) /* Running as a service */
{
char errbuf[2048]; /* Arbitrary size? */
vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
write_eventlog(ERROR, errbuf);
write_eventlog(ERROR, errbuf, strlen(errbuf));
}
else
{
/* Not running as service, write to stderr */
vfprintf(stderr, fmt, ap);
write_console(errbuf, strlen(errbuf));
fflush(stderr);
}
#endif

View File

@ -2,7 +2,7 @@
* Encoding names and routines for work with it. All
* in this file is shared bedween FE and BE.
*
* $PostgreSQL: pgsql/src/backend/utils/mb/encnames.c,v 1.39 2009/04/24 08:43:50 mha Exp $
* $PostgreSQL: pgsql/src/backend/utils/mb/encnames.c,v 1.40 2009/10/17 00:24:51 mha Exp $
*/
#ifdef FRONTEND
#include "postgres_fe.h"
@ -300,134 +300,55 @@ sizeof(pg_encname_tbl) / sizeof(pg_encname_tbl[0]) - 1;
* XXX must be sorted by the same order as enum pg_enc (in mb/pg_wchar.h)
* ----------
*/
#ifndef WIN32
#define DEF_ENC2NAME(name, codepage) { #name, PG_##name }
#else
#define DEF_ENC2NAME(name, codepage) { #name, PG_##name, codepage }
#endif
pg_enc2name pg_enc2name_tbl[] =
{
{
"SQL_ASCII", PG_SQL_ASCII
},
{
"EUC_JP", PG_EUC_JP
},
{
"EUC_CN", PG_EUC_CN
},
{
"EUC_KR", PG_EUC_KR
},
{
"EUC_TW", PG_EUC_TW
},
{
"EUC_JIS_2004", PG_EUC_JIS_2004
},
{
"UTF8", PG_UTF8
},
{
"MULE_INTERNAL", PG_MULE_INTERNAL
},
{
"LATIN1", PG_LATIN1
},
{
"LATIN2", PG_LATIN2
},
{
"LATIN3", PG_LATIN3
},
{
"LATIN4", PG_LATIN4
},
{
"LATIN5", PG_LATIN5
},
{
"LATIN6", PG_LATIN6
},
{
"LATIN7", PG_LATIN7
},
{
"LATIN8", PG_LATIN8
},
{
"LATIN9", PG_LATIN9
},
{
"LATIN10", PG_LATIN10
},
{
"WIN1256", PG_WIN1256
},
{
"WIN1258", PG_WIN1258
},
{
"WIN866", PG_WIN866
},
{
"WIN874", PG_WIN874
},
{
"KOI8R", PG_KOI8R
},
{
"WIN1251", PG_WIN1251
},
{
"WIN1252", PG_WIN1252
},
{
"ISO_8859_5", PG_ISO_8859_5
},
{
"ISO_8859_6", PG_ISO_8859_6
},
{
"ISO_8859_7", PG_ISO_8859_7
},
{
"ISO_8859_8", PG_ISO_8859_8
},
{
"WIN1250", PG_WIN1250
},
{
"WIN1253", PG_WIN1253
},
{
"WIN1254", PG_WIN1254
},
{
"WIN1255", PG_WIN1255
},
{
"WIN1257", PG_WIN1257
},
{
"KOI8U", PG_KOI8U
},
{
"SJIS", PG_SJIS
},
{
"BIG5", PG_BIG5
},
{
"GBK", PG_GBK
},
{
"UHC", PG_UHC
},
{
"GB18030", PG_GB18030
},
{
"JOHAB", PG_JOHAB
},
{
"SHIFT_JIS_2004", PG_SHIFT_JIS_2004
}
DEF_ENC2NAME(SQL_ASCII, 0),
DEF_ENC2NAME(EUC_JP, 20932),
DEF_ENC2NAME(EUC_CN, 20936),
DEF_ENC2NAME(EUC_KR, 51949),
DEF_ENC2NAME(EUC_TW, 0),
DEF_ENC2NAME(EUC_JIS_2004, 20932),
DEF_ENC2NAME(UTF8, 65001),
DEF_ENC2NAME(MULE_INTERNAL, 0),
DEF_ENC2NAME(LATIN1, 28591),
DEF_ENC2NAME(LATIN2, 28592),
DEF_ENC2NAME(LATIN3, 28593),
DEF_ENC2NAME(LATIN4, 28594),
DEF_ENC2NAME(LATIN5, 28599),
DEF_ENC2NAME(LATIN6, 0),
DEF_ENC2NAME(LATIN7, 0),
DEF_ENC2NAME(LATIN8, 0),
DEF_ENC2NAME(LATIN9, 28605),
DEF_ENC2NAME(LATIN10, 0),
DEF_ENC2NAME(WIN1256, 1256),
DEF_ENC2NAME(WIN1258, 1258),
DEF_ENC2NAME(WIN866, 866),
DEF_ENC2NAME(WIN874, 874),
DEF_ENC2NAME(KOI8R, 20866),
DEF_ENC2NAME(WIN1251, 1251),
DEF_ENC2NAME(WIN1252, 1252),
DEF_ENC2NAME(ISO_8859_5, 28595),
DEF_ENC2NAME(ISO_8859_6, 28596),
DEF_ENC2NAME(ISO_8859_7, 28597),
DEF_ENC2NAME(ISO_8859_8, 28598),
DEF_ENC2NAME(WIN1250, 1250),
DEF_ENC2NAME(WIN1253, 1253),
DEF_ENC2NAME(WIN1254, 1254),
DEF_ENC2NAME(WIN1255, 1255),
DEF_ENC2NAME(WIN1257, 1257),
DEF_ENC2NAME(KOI8U, 21866),
DEF_ENC2NAME(SJIS, 932),
DEF_ENC2NAME(BIG5, 950),
DEF_ENC2NAME(GBK, 936),
DEF_ENC2NAME(UHC, 0),
DEF_ENC2NAME(GB18030, 54936),
DEF_ENC2NAME(JOHAB, 0),
DEF_ENC2NAME(SHIFT_JIS_2004, 932)
};
/* ----------

View File

@ -4,7 +4,7 @@
*
* Tatsuo Ishii
*
* $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.89 2009/07/07 19:28:56 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.90 2009/10/17 00:24:51 mha Exp $
*/
#include "postgres.h"
@ -58,6 +58,7 @@ static FmgrInfo *ToClientConvProc = NULL;
*/
static pg_enc2name *ClientEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
static pg_enc2name *DatabaseEncoding = &pg_enc2name_tbl[PG_SQL_ASCII];
static pg_enc2name *PlatformEncoding = NULL;
/*
* During backend startup we can't set client encoding because we (a)
@ -978,3 +979,66 @@ pg_client_encoding(PG_FUNCTION_ARGS)
Assert(ClientEncoding);
return DirectFunctionCall1(namein, CStringGetDatum(ClientEncoding->name));
}
int
GetPlatformEncoding(void)
{
if (PlatformEncoding == NULL)
PlatformEncoding = &pg_enc2name_tbl[pg_get_encoding_from_locale("")];
return PlatformEncoding->encoding;
}
#ifdef WIN32
/*
* Result is palloc'ed null-terminated utf16 string. The character length
* is also passed to utf16len if not null. Returns NULL iff failed.
*/
WCHAR *
pgwin32_toUTF16(const char *str, int len, int *utf16len)
{
WCHAR *utf16;
int dstlen;
UINT codepage;
codepage = pg_enc2name_tbl[GetDatabaseEncoding()].codepage;
/*
* Use MultiByteToWideChar directly if there is a corresponding codepage,
* or double conversion through UTF8 if not.
*/
if (codepage != 0)
{
utf16 = (WCHAR *) palloc(sizeof(WCHAR) * (len + 1));
dstlen = MultiByteToWideChar(codepage, 0, str, len, utf16, len);
utf16[dstlen] = L'\0';
}
else
{
char *utf8;
utf8 = (char *) pg_do_encoding_conversion((unsigned char *) str,
len, GetDatabaseEncoding(), PG_UTF8);
if (utf8 != str)
len = strlen(utf8);
utf16 = (WCHAR *) palloc(sizeof(WCHAR) * (len + 1));
dstlen = MultiByteToWideChar(CP_UTF8, 0, utf8, len, utf16, len);
utf16[dstlen] = L'\0';
if (utf8 != str)
pfree(utf8);
}
if (dstlen == 0 && len > 0)
{
pfree(utf16);
return NULL; /* error */
}
if (utf16len)
*utf16len = len;
return utf16;
}
#endif

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/mb/pg_wchar.h,v 1.91 2009/06/11 14:49:11 momjian Exp $
* $PostgreSQL: pgsql/src/include/mb/pg_wchar.h,v 1.92 2009/10/17 00:24:51 mha Exp $
*
* NOTES
* This is used both by the backend and by libpq, but should not be
@ -257,6 +257,9 @@ typedef struct pg_enc2name
{
char *name;
pg_enc encoding;
#ifdef WIN32
unsigned codepage; /* codepage for WIN32 */
#endif
} pg_enc2name;
extern pg_enc2name pg_enc2name_tbl[];
@ -402,6 +405,7 @@ extern const char *pg_get_client_encoding_name(void);
extern void SetDatabaseEncoding(int encoding);
extern int GetDatabaseEncoding(void);
extern const char *GetDatabaseEncodingName(void);
extern int GetPlatformEncoding(void);
extern void pg_bind_textdomain_codeset(const char *domainname);
extern int pg_valid_client_encoding(const char *name);
@ -458,4 +462,8 @@ extern void mic2latin_with_table(const unsigned char *mic, unsigned char *p,
extern bool pg_utf8_islegal(const unsigned char *source, int length);
#ifdef WIN32
extern WCHAR *pgwin32_toUTF16(const char *str, int len, int *utf16len);
#endif
#endif /* PG_WCHAR_H */