This commit is contained in:
@@ -1,15 +0,0 @@
|
||||
/{{NO_DEPENDENCIES}}
|
||||
// Microsoft Developer Studio generated include file.
|
||||
// Used by version.rc
|
||||
//
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 103
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
523
cpp/wiiuse/include/classfile_constants.h
Normal file
523
cpp/wiiuse/include/classfile_constants.h
Normal file
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CLASSFILE_CONSTANTS_H
|
||||
#define CLASSFILE_CONSTANTS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Flags */
|
||||
|
||||
enum {
|
||||
JVM_ACC_PUBLIC = 0x0001,
|
||||
JVM_ACC_PRIVATE = 0x0002,
|
||||
JVM_ACC_PROTECTED = 0x0004,
|
||||
JVM_ACC_STATIC = 0x0008,
|
||||
JVM_ACC_FINAL = 0x0010,
|
||||
JVM_ACC_SYNCHRONIZED = 0x0020,
|
||||
JVM_ACC_SUPER = 0x0020,
|
||||
JVM_ACC_VOLATILE = 0x0040,
|
||||
JVM_ACC_BRIDGE = 0x0040,
|
||||
JVM_ACC_TRANSIENT = 0x0080,
|
||||
JVM_ACC_VARARGS = 0x0080,
|
||||
JVM_ACC_NATIVE = 0x0100,
|
||||
JVM_ACC_INTERFACE = 0x0200,
|
||||
JVM_ACC_ABSTRACT = 0x0400,
|
||||
JVM_ACC_STRICT = 0x0800,
|
||||
JVM_ACC_SYNTHETIC = 0x1000,
|
||||
JVM_ACC_ANNOTATION = 0x2000,
|
||||
JVM_ACC_ENUM = 0x4000
|
||||
};
|
||||
|
||||
/* Used in newarray instruction. */
|
||||
|
||||
enum {
|
||||
JVM_T_BOOLEAN = 4,
|
||||
JVM_T_CHAR = 5,
|
||||
JVM_T_FLOAT = 6,
|
||||
JVM_T_DOUBLE = 7,
|
||||
JVM_T_BYTE = 8,
|
||||
JVM_T_SHORT = 9,
|
||||
JVM_T_INT = 10,
|
||||
JVM_T_LONG = 11
|
||||
};
|
||||
|
||||
/* Constant Pool Entries */
|
||||
|
||||
enum {
|
||||
JVM_CONSTANT_Utf8 = 1,
|
||||
JVM_CONSTANT_Unicode = 2, /* unused */
|
||||
JVM_CONSTANT_Integer = 3,
|
||||
JVM_CONSTANT_Float = 4,
|
||||
JVM_CONSTANT_Long = 5,
|
||||
JVM_CONSTANT_Double = 6,
|
||||
JVM_CONSTANT_Class = 7,
|
||||
JVM_CONSTANT_String = 8,
|
||||
JVM_CONSTANT_Fieldref = 9,
|
||||
JVM_CONSTANT_Methodref = 10,
|
||||
JVM_CONSTANT_InterfaceMethodref = 11,
|
||||
JVM_CONSTANT_NameAndType = 12
|
||||
};
|
||||
|
||||
/* StackMapTable type item numbers */
|
||||
|
||||
enum {
|
||||
JVM_ITEM_Top = 0,
|
||||
JVM_ITEM_Integer = 1,
|
||||
JVM_ITEM_Float = 2,
|
||||
JVM_ITEM_Double = 3,
|
||||
JVM_ITEM_Long = 4,
|
||||
JVM_ITEM_Null = 5,
|
||||
JVM_ITEM_UninitializedThis = 6,
|
||||
JVM_ITEM_Object = 7,
|
||||
JVM_ITEM_Uninitialized = 8
|
||||
};
|
||||
|
||||
/* Type signatures */
|
||||
|
||||
enum {
|
||||
JVM_SIGNATURE_ARRAY = '[',
|
||||
JVM_SIGNATURE_BYTE = 'B',
|
||||
JVM_SIGNATURE_CHAR = 'C',
|
||||
JVM_SIGNATURE_CLASS = 'L',
|
||||
JVM_SIGNATURE_ENDCLASS = ';',
|
||||
JVM_SIGNATURE_ENUM = 'E',
|
||||
JVM_SIGNATURE_FLOAT = 'F',
|
||||
JVM_SIGNATURE_DOUBLE = 'D',
|
||||
JVM_SIGNATURE_FUNC = '(',
|
||||
JVM_SIGNATURE_ENDFUNC = ')',
|
||||
JVM_SIGNATURE_INT = 'I',
|
||||
JVM_SIGNATURE_LONG = 'J',
|
||||
JVM_SIGNATURE_SHORT = 'S',
|
||||
JVM_SIGNATURE_VOID = 'V',
|
||||
JVM_SIGNATURE_BOOLEAN = 'Z'
|
||||
};
|
||||
|
||||
/* Opcodes */
|
||||
|
||||
enum {
|
||||
JVM_OPC_nop = 0,
|
||||
JVM_OPC_aconst_null = 1,
|
||||
JVM_OPC_iconst_m1 = 2,
|
||||
JVM_OPC_iconst_0 = 3,
|
||||
JVM_OPC_iconst_1 = 4,
|
||||
JVM_OPC_iconst_2 = 5,
|
||||
JVM_OPC_iconst_3 = 6,
|
||||
JVM_OPC_iconst_4 = 7,
|
||||
JVM_OPC_iconst_5 = 8,
|
||||
JVM_OPC_lconst_0 = 9,
|
||||
JVM_OPC_lconst_1 = 10,
|
||||
JVM_OPC_fconst_0 = 11,
|
||||
JVM_OPC_fconst_1 = 12,
|
||||
JVM_OPC_fconst_2 = 13,
|
||||
JVM_OPC_dconst_0 = 14,
|
||||
JVM_OPC_dconst_1 = 15,
|
||||
JVM_OPC_bipush = 16,
|
||||
JVM_OPC_sipush = 17,
|
||||
JVM_OPC_ldc = 18,
|
||||
JVM_OPC_ldc_w = 19,
|
||||
JVM_OPC_ldc2_w = 20,
|
||||
JVM_OPC_iload = 21,
|
||||
JVM_OPC_lload = 22,
|
||||
JVM_OPC_fload = 23,
|
||||
JVM_OPC_dload = 24,
|
||||
JVM_OPC_aload = 25,
|
||||
JVM_OPC_iload_0 = 26,
|
||||
JVM_OPC_iload_1 = 27,
|
||||
JVM_OPC_iload_2 = 28,
|
||||
JVM_OPC_iload_3 = 29,
|
||||
JVM_OPC_lload_0 = 30,
|
||||
JVM_OPC_lload_1 = 31,
|
||||
JVM_OPC_lload_2 = 32,
|
||||
JVM_OPC_lload_3 = 33,
|
||||
JVM_OPC_fload_0 = 34,
|
||||
JVM_OPC_fload_1 = 35,
|
||||
JVM_OPC_fload_2 = 36,
|
||||
JVM_OPC_fload_3 = 37,
|
||||
JVM_OPC_dload_0 = 38,
|
||||
JVM_OPC_dload_1 = 39,
|
||||
JVM_OPC_dload_2 = 40,
|
||||
JVM_OPC_dload_3 = 41,
|
||||
JVM_OPC_aload_0 = 42,
|
||||
JVM_OPC_aload_1 = 43,
|
||||
JVM_OPC_aload_2 = 44,
|
||||
JVM_OPC_aload_3 = 45,
|
||||
JVM_OPC_iaload = 46,
|
||||
JVM_OPC_laload = 47,
|
||||
JVM_OPC_faload = 48,
|
||||
JVM_OPC_daload = 49,
|
||||
JVM_OPC_aaload = 50,
|
||||
JVM_OPC_baload = 51,
|
||||
JVM_OPC_caload = 52,
|
||||
JVM_OPC_saload = 53,
|
||||
JVM_OPC_istore = 54,
|
||||
JVM_OPC_lstore = 55,
|
||||
JVM_OPC_fstore = 56,
|
||||
JVM_OPC_dstore = 57,
|
||||
JVM_OPC_astore = 58,
|
||||
JVM_OPC_istore_0 = 59,
|
||||
JVM_OPC_istore_1 = 60,
|
||||
JVM_OPC_istore_2 = 61,
|
||||
JVM_OPC_istore_3 = 62,
|
||||
JVM_OPC_lstore_0 = 63,
|
||||
JVM_OPC_lstore_1 = 64,
|
||||
JVM_OPC_lstore_2 = 65,
|
||||
JVM_OPC_lstore_3 = 66,
|
||||
JVM_OPC_fstore_0 = 67,
|
||||
JVM_OPC_fstore_1 = 68,
|
||||
JVM_OPC_fstore_2 = 69,
|
||||
JVM_OPC_fstore_3 = 70,
|
||||
JVM_OPC_dstore_0 = 71,
|
||||
JVM_OPC_dstore_1 = 72,
|
||||
JVM_OPC_dstore_2 = 73,
|
||||
JVM_OPC_dstore_3 = 74,
|
||||
JVM_OPC_astore_0 = 75,
|
||||
JVM_OPC_astore_1 = 76,
|
||||
JVM_OPC_astore_2 = 77,
|
||||
JVM_OPC_astore_3 = 78,
|
||||
JVM_OPC_iastore = 79,
|
||||
JVM_OPC_lastore = 80,
|
||||
JVM_OPC_fastore = 81,
|
||||
JVM_OPC_dastore = 82,
|
||||
JVM_OPC_aastore = 83,
|
||||
JVM_OPC_bastore = 84,
|
||||
JVM_OPC_castore = 85,
|
||||
JVM_OPC_sastore = 86,
|
||||
JVM_OPC_pop = 87,
|
||||
JVM_OPC_pop2 = 88,
|
||||
JVM_OPC_dup = 89,
|
||||
JVM_OPC_dup_x1 = 90,
|
||||
JVM_OPC_dup_x2 = 91,
|
||||
JVM_OPC_dup2 = 92,
|
||||
JVM_OPC_dup2_x1 = 93,
|
||||
JVM_OPC_dup2_x2 = 94,
|
||||
JVM_OPC_swap = 95,
|
||||
JVM_OPC_iadd = 96,
|
||||
JVM_OPC_ladd = 97,
|
||||
JVM_OPC_fadd = 98,
|
||||
JVM_OPC_dadd = 99,
|
||||
JVM_OPC_isub = 100,
|
||||
JVM_OPC_lsub = 101,
|
||||
JVM_OPC_fsub = 102,
|
||||
JVM_OPC_dsub = 103,
|
||||
JVM_OPC_imul = 104,
|
||||
JVM_OPC_lmul = 105,
|
||||
JVM_OPC_fmul = 106,
|
||||
JVM_OPC_dmul = 107,
|
||||
JVM_OPC_idiv = 108,
|
||||
JVM_OPC_ldiv = 109,
|
||||
JVM_OPC_fdiv = 110,
|
||||
JVM_OPC_ddiv = 111,
|
||||
JVM_OPC_irem = 112,
|
||||
JVM_OPC_lrem = 113,
|
||||
JVM_OPC_frem = 114,
|
||||
JVM_OPC_drem = 115,
|
||||
JVM_OPC_ineg = 116,
|
||||
JVM_OPC_lneg = 117,
|
||||
JVM_OPC_fneg = 118,
|
||||
JVM_OPC_dneg = 119,
|
||||
JVM_OPC_ishl = 120,
|
||||
JVM_OPC_lshl = 121,
|
||||
JVM_OPC_ishr = 122,
|
||||
JVM_OPC_lshr = 123,
|
||||
JVM_OPC_iushr = 124,
|
||||
JVM_OPC_lushr = 125,
|
||||
JVM_OPC_iand = 126,
|
||||
JVM_OPC_land = 127,
|
||||
JVM_OPC_ior = 128,
|
||||
JVM_OPC_lor = 129,
|
||||
JVM_OPC_ixor = 130,
|
||||
JVM_OPC_lxor = 131,
|
||||
JVM_OPC_iinc = 132,
|
||||
JVM_OPC_i2l = 133,
|
||||
JVM_OPC_i2f = 134,
|
||||
JVM_OPC_i2d = 135,
|
||||
JVM_OPC_l2i = 136,
|
||||
JVM_OPC_l2f = 137,
|
||||
JVM_OPC_l2d = 138,
|
||||
JVM_OPC_f2i = 139,
|
||||
JVM_OPC_f2l = 140,
|
||||
JVM_OPC_f2d = 141,
|
||||
JVM_OPC_d2i = 142,
|
||||
JVM_OPC_d2l = 143,
|
||||
JVM_OPC_d2f = 144,
|
||||
JVM_OPC_i2b = 145,
|
||||
JVM_OPC_i2c = 146,
|
||||
JVM_OPC_i2s = 147,
|
||||
JVM_OPC_lcmp = 148,
|
||||
JVM_OPC_fcmpl = 149,
|
||||
JVM_OPC_fcmpg = 150,
|
||||
JVM_OPC_dcmpl = 151,
|
||||
JVM_OPC_dcmpg = 152,
|
||||
JVM_OPC_ifeq = 153,
|
||||
JVM_OPC_ifne = 154,
|
||||
JVM_OPC_iflt = 155,
|
||||
JVM_OPC_ifge = 156,
|
||||
JVM_OPC_ifgt = 157,
|
||||
JVM_OPC_ifle = 158,
|
||||
JVM_OPC_if_icmpeq = 159,
|
||||
JVM_OPC_if_icmpne = 160,
|
||||
JVM_OPC_if_icmplt = 161,
|
||||
JVM_OPC_if_icmpge = 162,
|
||||
JVM_OPC_if_icmpgt = 163,
|
||||
JVM_OPC_if_icmple = 164,
|
||||
JVM_OPC_if_acmpeq = 165,
|
||||
JVM_OPC_if_acmpne = 166,
|
||||
JVM_OPC_goto = 167,
|
||||
JVM_OPC_jsr = 168,
|
||||
JVM_OPC_ret = 169,
|
||||
JVM_OPC_tableswitch = 170,
|
||||
JVM_OPC_lookupswitch = 171,
|
||||
JVM_OPC_ireturn = 172,
|
||||
JVM_OPC_lreturn = 173,
|
||||
JVM_OPC_freturn = 174,
|
||||
JVM_OPC_dreturn = 175,
|
||||
JVM_OPC_areturn = 176,
|
||||
JVM_OPC_return = 177,
|
||||
JVM_OPC_getstatic = 178,
|
||||
JVM_OPC_putstatic = 179,
|
||||
JVM_OPC_getfield = 180,
|
||||
JVM_OPC_putfield = 181,
|
||||
JVM_OPC_invokevirtual = 182,
|
||||
JVM_OPC_invokespecial = 183,
|
||||
JVM_OPC_invokestatic = 184,
|
||||
JVM_OPC_invokeinterface = 185,
|
||||
JVM_OPC_xxxunusedxxx = 186,
|
||||
JVM_OPC_new = 187,
|
||||
JVM_OPC_newarray = 188,
|
||||
JVM_OPC_anewarray = 189,
|
||||
JVM_OPC_arraylength = 190,
|
||||
JVM_OPC_athrow = 191,
|
||||
JVM_OPC_checkcast = 192,
|
||||
JVM_OPC_instanceof = 193,
|
||||
JVM_OPC_monitorenter = 194,
|
||||
JVM_OPC_monitorexit = 195,
|
||||
JVM_OPC_wide = 196,
|
||||
JVM_OPC_multianewarray = 197,
|
||||
JVM_OPC_ifnull = 198,
|
||||
JVM_OPC_ifnonnull = 199,
|
||||
JVM_OPC_goto_w = 200,
|
||||
JVM_OPC_jsr_w = 201,
|
||||
JVM_OPC_MAX = 201
|
||||
};
|
||||
|
||||
/* Opcode length initializer, use with something like:
|
||||
* unsigned char opcode_length[JVM_OPC_MAX+1] = JVM_OPCODE_LENGTH_INITIALIZER;
|
||||
*/
|
||||
#define JVM_OPCODE_LENGTH_INITIALIZER { \
|
||||
1, /* nop */ \
|
||||
1, /* aconst_null */ \
|
||||
1, /* iconst_m1 */ \
|
||||
1, /* iconst_0 */ \
|
||||
1, /* iconst_1 */ \
|
||||
1, /* iconst_2 */ \
|
||||
1, /* iconst_3 */ \
|
||||
1, /* iconst_4 */ \
|
||||
1, /* iconst_5 */ \
|
||||
1, /* lconst_0 */ \
|
||||
1, /* lconst_1 */ \
|
||||
1, /* fconst_0 */ \
|
||||
1, /* fconst_1 */ \
|
||||
1, /* fconst_2 */ \
|
||||
1, /* dconst_0 */ \
|
||||
1, /* dconst_1 */ \
|
||||
2, /* bipush */ \
|
||||
3, /* sipush */ \
|
||||
2, /* ldc */ \
|
||||
3, /* ldc_w */ \
|
||||
3, /* ldc2_w */ \
|
||||
2, /* iload */ \
|
||||
2, /* lload */ \
|
||||
2, /* fload */ \
|
||||
2, /* dload */ \
|
||||
2, /* aload */ \
|
||||
1, /* iload_0 */ \
|
||||
1, /* iload_1 */ \
|
||||
1, /* iload_2 */ \
|
||||
1, /* iload_3 */ \
|
||||
1, /* lload_0 */ \
|
||||
1, /* lload_1 */ \
|
||||
1, /* lload_2 */ \
|
||||
1, /* lload_3 */ \
|
||||
1, /* fload_0 */ \
|
||||
1, /* fload_1 */ \
|
||||
1, /* fload_2 */ \
|
||||
1, /* fload_3 */ \
|
||||
1, /* dload_0 */ \
|
||||
1, /* dload_1 */ \
|
||||
1, /* dload_2 */ \
|
||||
1, /* dload_3 */ \
|
||||
1, /* aload_0 */ \
|
||||
1, /* aload_1 */ \
|
||||
1, /* aload_2 */ \
|
||||
1, /* aload_3 */ \
|
||||
1, /* iaload */ \
|
||||
1, /* laload */ \
|
||||
1, /* faload */ \
|
||||
1, /* daload */ \
|
||||
1, /* aaload */ \
|
||||
1, /* baload */ \
|
||||
1, /* caload */ \
|
||||
1, /* saload */ \
|
||||
2, /* istore */ \
|
||||
2, /* lstore */ \
|
||||
2, /* fstore */ \
|
||||
2, /* dstore */ \
|
||||
2, /* astore */ \
|
||||
1, /* istore_0 */ \
|
||||
1, /* istore_1 */ \
|
||||
1, /* istore_2 */ \
|
||||
1, /* istore_3 */ \
|
||||
1, /* lstore_0 */ \
|
||||
1, /* lstore_1 */ \
|
||||
1, /* lstore_2 */ \
|
||||
1, /* lstore_3 */ \
|
||||
1, /* fstore_0 */ \
|
||||
1, /* fstore_1 */ \
|
||||
1, /* fstore_2 */ \
|
||||
1, /* fstore_3 */ \
|
||||
1, /* dstore_0 */ \
|
||||
1, /* dstore_1 */ \
|
||||
1, /* dstore_2 */ \
|
||||
1, /* dstore_3 */ \
|
||||
1, /* astore_0 */ \
|
||||
1, /* astore_1 */ \
|
||||
1, /* astore_2 */ \
|
||||
1, /* astore_3 */ \
|
||||
1, /* iastore */ \
|
||||
1, /* lastore */ \
|
||||
1, /* fastore */ \
|
||||
1, /* dastore */ \
|
||||
1, /* aastore */ \
|
||||
1, /* bastore */ \
|
||||
1, /* castore */ \
|
||||
1, /* sastore */ \
|
||||
1, /* pop */ \
|
||||
1, /* pop2 */ \
|
||||
1, /* dup */ \
|
||||
1, /* dup_x1 */ \
|
||||
1, /* dup_x2 */ \
|
||||
1, /* dup2 */ \
|
||||
1, /* dup2_x1 */ \
|
||||
1, /* dup2_x2 */ \
|
||||
1, /* swap */ \
|
||||
1, /* iadd */ \
|
||||
1, /* ladd */ \
|
||||
1, /* fadd */ \
|
||||
1, /* dadd */ \
|
||||
1, /* isub */ \
|
||||
1, /* lsub */ \
|
||||
1, /* fsub */ \
|
||||
1, /* dsub */ \
|
||||
1, /* imul */ \
|
||||
1, /* lmul */ \
|
||||
1, /* fmul */ \
|
||||
1, /* dmul */ \
|
||||
1, /* idiv */ \
|
||||
1, /* ldiv */ \
|
||||
1, /* fdiv */ \
|
||||
1, /* ddiv */ \
|
||||
1, /* irem */ \
|
||||
1, /* lrem */ \
|
||||
1, /* frem */ \
|
||||
1, /* drem */ \
|
||||
1, /* ineg */ \
|
||||
1, /* lneg */ \
|
||||
1, /* fneg */ \
|
||||
1, /* dneg */ \
|
||||
1, /* ishl */ \
|
||||
1, /* lshl */ \
|
||||
1, /* ishr */ \
|
||||
1, /* lshr */ \
|
||||
1, /* iushr */ \
|
||||
1, /* lushr */ \
|
||||
1, /* iand */ \
|
||||
1, /* land */ \
|
||||
1, /* ior */ \
|
||||
1, /* lor */ \
|
||||
1, /* ixor */ \
|
||||
1, /* lxor */ \
|
||||
3, /* iinc */ \
|
||||
1, /* i2l */ \
|
||||
1, /* i2f */ \
|
||||
1, /* i2d */ \
|
||||
1, /* l2i */ \
|
||||
1, /* l2f */ \
|
||||
1, /* l2d */ \
|
||||
1, /* f2i */ \
|
||||
1, /* f2l */ \
|
||||
1, /* f2d */ \
|
||||
1, /* d2i */ \
|
||||
1, /* d2l */ \
|
||||
1, /* d2f */ \
|
||||
1, /* i2b */ \
|
||||
1, /* i2c */ \
|
||||
1, /* i2s */ \
|
||||
1, /* lcmp */ \
|
||||
1, /* fcmpl */ \
|
||||
1, /* fcmpg */ \
|
||||
1, /* dcmpl */ \
|
||||
1, /* dcmpg */ \
|
||||
3, /* ifeq */ \
|
||||
3, /* ifne */ \
|
||||
3, /* iflt */ \
|
||||
3, /* ifge */ \
|
||||
3, /* ifgt */ \
|
||||
3, /* ifle */ \
|
||||
3, /* if_icmpeq */ \
|
||||
3, /* if_icmpne */ \
|
||||
3, /* if_icmplt */ \
|
||||
3, /* if_icmpge */ \
|
||||
3, /* if_icmpgt */ \
|
||||
3, /* if_icmple */ \
|
||||
3, /* if_acmpeq */ \
|
||||
3, /* if_acmpne */ \
|
||||
3, /* goto */ \
|
||||
3, /* jsr */ \
|
||||
2, /* ret */ \
|
||||
99, /* tableswitch */ \
|
||||
99, /* lookupswitch */ \
|
||||
1, /* ireturn */ \
|
||||
1, /* lreturn */ \
|
||||
1, /* freturn */ \
|
||||
1, /* dreturn */ \
|
||||
1, /* areturn */ \
|
||||
1, /* return */ \
|
||||
3, /* getstatic */ \
|
||||
3, /* putstatic */ \
|
||||
3, /* getfield */ \
|
||||
3, /* putfield */ \
|
||||
3, /* invokevirtual */ \
|
||||
3, /* invokespecial */ \
|
||||
3, /* invokestatic */ \
|
||||
5, /* invokeinterface */ \
|
||||
0, /* xxxunusedxxx */ \
|
||||
3, /* new */ \
|
||||
2, /* newarray */ \
|
||||
3, /* anewarray */ \
|
||||
1, /* arraylength */ \
|
||||
1, /* athrow */ \
|
||||
3, /* checkcast */ \
|
||||
3, /* instanceof */ \
|
||||
1, /* monitorenter */ \
|
||||
1, /* monitorexit */ \
|
||||
0, /* wide */ \
|
||||
4, /* multianewarray */ \
|
||||
3, /* ifnull */ \
|
||||
3, /* ifnonnull */ \
|
||||
5, /* goto_w */ \
|
||||
5 /* jsr_w */ \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* CLASSFILE_CONSTANTS */
|
||||
278
cpp/wiiuse/include/jawt.h
Normal file
278
cpp/wiiuse/include/jawt.h
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JAWT_H_
|
||||
#define _JAVASOFT_JAWT_H_
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AWT native interface (new in JDK 1.3)
|
||||
*
|
||||
* The AWT native interface allows a native C or C++ application a means
|
||||
* by which to access native structures in AWT. This is to facilitate moving
|
||||
* legacy C and C++ applications to Java and to target the needs of the
|
||||
* community who, at present, wish to do their own native rendering to canvases
|
||||
* for performance reasons. Standard extensions such as Java3D also require a
|
||||
* means to access the underlying native data structures of AWT.
|
||||
*
|
||||
* There may be future extensions to this API depending on demand.
|
||||
*
|
||||
* A VM does not have to implement this API in order to pass the JCK.
|
||||
* It is recommended, however, that this API is implemented on VMs that support
|
||||
* standard extensions, such as Java3D.
|
||||
*
|
||||
* Since this is a native API, any program which uses it cannot be considered
|
||||
* 100% pure java.
|
||||
*/
|
||||
|
||||
/*
|
||||
* AWT Native Drawing Surface (JAWT_DrawingSurface).
|
||||
*
|
||||
* For each platform, there is a native drawing surface structure. This
|
||||
* platform-specific structure can be found in jawt_md.h. It is recommended
|
||||
* that additional platforms follow the same model. It is also recommended
|
||||
* that VMs on Win32 and Solaris support the existing structures in jawt_md.h.
|
||||
*
|
||||
*******************
|
||||
* EXAMPLE OF USAGE:
|
||||
*******************
|
||||
*
|
||||
* In Win32, a programmer wishes to access the HWND of a canvas to perform
|
||||
* native rendering into it. The programmer has declared the paint() method
|
||||
* for their canvas subclass to be native:
|
||||
*
|
||||
*
|
||||
* MyCanvas.java:
|
||||
*
|
||||
* import java.awt.*;
|
||||
*
|
||||
* public class MyCanvas extends Canvas {
|
||||
*
|
||||
* static {
|
||||
* System.loadLibrary("mylib");
|
||||
* }
|
||||
*
|
||||
* public native void paint(Graphics g);
|
||||
* }
|
||||
*
|
||||
*
|
||||
* myfile.c:
|
||||
*
|
||||
* #include "jawt_md.h"
|
||||
* #include <assert.h>
|
||||
*
|
||||
* JNIEXPORT void JNICALL
|
||||
* Java_MyCanvas_paint(JNIEnv* env, jobject canvas, jobject graphics)
|
||||
* {
|
||||
* JAWT awt;
|
||||
* JAWT_DrawingSurface* ds;
|
||||
* JAWT_DrawingSurfaceInfo* dsi;
|
||||
* JAWT_Win32DrawingSurfaceInfo* dsi_win;
|
||||
* jboolean result;
|
||||
* jint lock;
|
||||
*
|
||||
* // Get the AWT
|
||||
* awt.version = JAWT_VERSION_1_3;
|
||||
* result = JAWT_GetAWT(env, &awt);
|
||||
* assert(result != JNI_FALSE);
|
||||
*
|
||||
* // Get the drawing surface
|
||||
* ds = awt.GetDrawingSurface(env, canvas);
|
||||
* assert(ds != NULL);
|
||||
*
|
||||
* // Lock the drawing surface
|
||||
* lock = ds->Lock(ds);
|
||||
* assert((lock & JAWT_LOCK_ERROR) == 0);
|
||||
*
|
||||
* // Get the drawing surface info
|
||||
* dsi = ds->GetDrawingSurfaceInfo(ds);
|
||||
*
|
||||
* // Get the platform-specific drawing info
|
||||
* dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
|
||||
*
|
||||
* //////////////////////////////
|
||||
* // !!! DO PAINTING HERE !!! //
|
||||
* //////////////////////////////
|
||||
*
|
||||
* // Free the drawing surface info
|
||||
* ds->FreeDrawingSurfaceInfo(dsi);
|
||||
*
|
||||
* // Unlock the drawing surface
|
||||
* ds->Unlock(ds);
|
||||
*
|
||||
* // Free the drawing surface
|
||||
* awt.FreeDrawingSurface(ds);
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* JAWT_Rectangle
|
||||
* Structure for a native rectangle.
|
||||
*/
|
||||
typedef struct jawt_Rectangle {
|
||||
jint x;
|
||||
jint y;
|
||||
jint width;
|
||||
jint height;
|
||||
} JAWT_Rectangle;
|
||||
|
||||
struct jawt_DrawingSurface;
|
||||
|
||||
/*
|
||||
* JAWT_DrawingSurfaceInfo
|
||||
* Structure for containing the underlying drawing information of a component.
|
||||
*/
|
||||
typedef struct jawt_DrawingSurfaceInfo {
|
||||
/*
|
||||
* Pointer to the platform-specific information. This can be safely
|
||||
* cast to a JAWT_Win32DrawingSurfaceInfo on Windows or a
|
||||
* JAWT_X11DrawingSurfaceInfo on Solaris. See jawt_md.h for details.
|
||||
*/
|
||||
void* platformInfo;
|
||||
/* Cached pointer to the underlying drawing surface */
|
||||
struct jawt_DrawingSurface* ds;
|
||||
/* Bounding rectangle of the drawing surface */
|
||||
JAWT_Rectangle bounds;
|
||||
/* Number of rectangles in the clip */
|
||||
jint clipSize;
|
||||
/* Clip rectangle array */
|
||||
JAWT_Rectangle* clip;
|
||||
} JAWT_DrawingSurfaceInfo;
|
||||
|
||||
#define JAWT_LOCK_ERROR 0x00000001
|
||||
#define JAWT_LOCK_CLIP_CHANGED 0x00000002
|
||||
#define JAWT_LOCK_BOUNDS_CHANGED 0x00000004
|
||||
#define JAWT_LOCK_SURFACE_CHANGED 0x00000008
|
||||
|
||||
/*
|
||||
* JAWT_DrawingSurface
|
||||
* Structure for containing the underlying drawing information of a component.
|
||||
* All operations on a JAWT_DrawingSurface MUST be performed from the same
|
||||
* thread as the call to GetDrawingSurface.
|
||||
*/
|
||||
typedef struct jawt_DrawingSurface {
|
||||
/*
|
||||
* Cached reference to the Java environment of the calling thread.
|
||||
* If Lock(), Unlock(), GetDrawingSurfaceInfo() or
|
||||
* FreeDrawingSurfaceInfo() are called from a different thread,
|
||||
* this data member should be set before calling those functions.
|
||||
*/
|
||||
JNIEnv* env;
|
||||
/* Cached reference to the target object */
|
||||
jobject target;
|
||||
/*
|
||||
* Lock the surface of the target component for native rendering.
|
||||
* When finished drawing, the surface must be unlocked with
|
||||
* Unlock(). This function returns a bitmask with one or more of the
|
||||
* following values:
|
||||
*
|
||||
* JAWT_LOCK_ERROR - When an error has occurred and the surface could not
|
||||
* be locked.
|
||||
*
|
||||
* JAWT_LOCK_CLIP_CHANGED - When the clip region has changed.
|
||||
*
|
||||
* JAWT_LOCK_BOUNDS_CHANGED - When the bounds of the surface have changed.
|
||||
*
|
||||
* JAWT_LOCK_SURFACE_CHANGED - When the surface itself has changed
|
||||
*/
|
||||
jint (JNICALL *Lock)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
/*
|
||||
* Get the drawing surface info.
|
||||
* The value returned may be cached, but the values may change if
|
||||
* additional calls to Lock() or Unlock() are made.
|
||||
* Lock() must be called before this can return a valid value.
|
||||
* Returns NULL if an error has occurred.
|
||||
* When finished with the returned value, FreeDrawingSurfaceInfo must be
|
||||
* called.
|
||||
*/
|
||||
JAWT_DrawingSurfaceInfo* (JNICALL *GetDrawingSurfaceInfo)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
/*
|
||||
* Free the drawing surface info.
|
||||
*/
|
||||
void (JNICALL *FreeDrawingSurfaceInfo)
|
||||
(JAWT_DrawingSurfaceInfo* dsi);
|
||||
/*
|
||||
* Unlock the drawing surface of the target component for native rendering.
|
||||
*/
|
||||
void (JNICALL *Unlock)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
} JAWT_DrawingSurface;
|
||||
|
||||
/*
|
||||
* JAWT
|
||||
* Structure for containing native AWT functions.
|
||||
*/
|
||||
typedef struct jawt {
|
||||
/*
|
||||
* Version of this structure. This must always be set before
|
||||
* calling JAWT_GetAWT()
|
||||
*/
|
||||
jint version;
|
||||
/*
|
||||
* Return a drawing surface from a target jobject. This value
|
||||
* may be cached.
|
||||
* Returns NULL if an error has occurred.
|
||||
* Target must be a java.awt.Component (should be a Canvas
|
||||
* or Window for native rendering).
|
||||
* FreeDrawingSurface() must be called when finished with the
|
||||
* returned JAWT_DrawingSurface.
|
||||
*/
|
||||
JAWT_DrawingSurface* (JNICALL *GetDrawingSurface)
|
||||
(JNIEnv* env, jobject target);
|
||||
/*
|
||||
* Free the drawing surface allocated in GetDrawingSurface.
|
||||
*/
|
||||
void (JNICALL *FreeDrawingSurface)
|
||||
(JAWT_DrawingSurface* ds);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Locks the entire AWT for synchronization purposes
|
||||
*/
|
||||
void (JNICALL *Lock)(JNIEnv* env);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Unlocks the entire AWT for synchronization purposes
|
||||
*/
|
||||
void (JNICALL *Unlock)(JNIEnv* env);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Returns a reference to a java.awt.Component from a native
|
||||
* platform handle. On Windows, this corresponds to an HWND;
|
||||
* on Solaris and Linux, this is a Drawable. For other platforms,
|
||||
* see the appropriate machine-dependent header file for a description.
|
||||
* The reference returned by this function is a local
|
||||
* reference that is only valid in this environment.
|
||||
* This function returns a NULL reference if no component could be
|
||||
* found with matching platform information.
|
||||
*/
|
||||
jobject (JNICALL *GetComponent)(JNIEnv* env, void* platformInfo);
|
||||
|
||||
} JAWT;
|
||||
|
||||
/*
|
||||
* Get the AWT native structure. This function returns JNI_FALSE if
|
||||
* an error occurs.
|
||||
*/
|
||||
_JNI_IMPORT_OR_EXPORT_
|
||||
jboolean JNICALL JAWT_GetAWT(JNIEnv* env, JAWT* awt);
|
||||
|
||||
#define JAWT_VERSION_1_3 0x00010003
|
||||
#define JAWT_VERSION_1_4 0x00010004
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* !_JAVASOFT_JAWT_H_ */
|
||||
237
cpp/wiiuse/include/jdwpTransport.h
Normal file
237
cpp/wiiuse/include/jdwpTransport.h
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Java Debug Wire Protocol Transport Service Provider Interface.
|
||||
*/
|
||||
|
||||
#ifndef JDWPTRANSPORT_H
|
||||
#define JDWPTRANSPORT_H
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
enum {
|
||||
JDWPTRANSPORT_VERSION_1_0 = 0x00010000
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct jdwpTransportNativeInterface_;
|
||||
|
||||
struct _jdwpTransportEnv;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef _jdwpTransportEnv jdwpTransportEnv;
|
||||
#else
|
||||
typedef const struct jdwpTransportNativeInterface_ *jdwpTransportEnv;
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Errors. Universal errors with JVMTI/JVMDI equivalents keep the
|
||||
* values the same.
|
||||
*/
|
||||
typedef enum {
|
||||
JDWPTRANSPORT_ERROR_NONE = 0,
|
||||
JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT = 103,
|
||||
JDWPTRANSPORT_ERROR_OUT_OF_MEMORY = 110,
|
||||
JDWPTRANSPORT_ERROR_INTERNAL = 113,
|
||||
JDWPTRANSPORT_ERROR_ILLEGAL_STATE = 201,
|
||||
JDWPTRANSPORT_ERROR_IO_ERROR = 202,
|
||||
JDWPTRANSPORT_ERROR_TIMEOUT = 203,
|
||||
JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE = 204
|
||||
} jdwpTransportError;
|
||||
|
||||
|
||||
/*
|
||||
* Structure to define capabilities
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int can_timeout_attach :1;
|
||||
unsigned int can_timeout_accept :1;
|
||||
unsigned int can_timeout_handshake :1;
|
||||
unsigned int reserved3 :1;
|
||||
unsigned int reserved4 :1;
|
||||
unsigned int reserved5 :1;
|
||||
unsigned int reserved6 :1;
|
||||
unsigned int reserved7 :1;
|
||||
unsigned int reserved8 :1;
|
||||
unsigned int reserved9 :1;
|
||||
unsigned int reserved10 :1;
|
||||
unsigned int reserved11 :1;
|
||||
unsigned int reserved12 :1;
|
||||
unsigned int reserved13 :1;
|
||||
unsigned int reserved14 :1;
|
||||
unsigned int reserved15 :1;
|
||||
} JDWPTransportCapabilities;
|
||||
|
||||
|
||||
/*
|
||||
* Structures to define packet layout.
|
||||
*
|
||||
* See: http://java.sun.com/j2se/1.5/docs/guide/jpda/jdwp-spec.html
|
||||
*/
|
||||
|
||||
enum {
|
||||
JDWPTRANSPORT_FLAGS_NONE = 0x0,
|
||||
JDWPTRANSPORT_FLAGS_REPLY = 0x80
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
jint len;
|
||||
jint id;
|
||||
jbyte flags;
|
||||
jbyte cmdSet;
|
||||
jbyte cmd;
|
||||
jbyte *data;
|
||||
} jdwpCmdPacket;
|
||||
|
||||
typedef struct {
|
||||
jint len;
|
||||
jint id;
|
||||
jbyte flags;
|
||||
jshort errorCode;
|
||||
jbyte *data;
|
||||
} jdwpReplyPacket;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
jdwpCmdPacket cmd;
|
||||
jdwpReplyPacket reply;
|
||||
} type;
|
||||
} jdwpPacket;
|
||||
|
||||
/*
|
||||
* JDWP functions called by the transport.
|
||||
*/
|
||||
typedef struct jdwpTransportCallback {
|
||||
void *(*alloc)(jint numBytes); /* Call this for all allocations */
|
||||
void (*free)(void *buffer); /* Call this for all deallocations */
|
||||
} jdwpTransportCallback;
|
||||
|
||||
typedef jint (JNICALL *jdwpTransport_OnLoad_t)(JavaVM *jvm,
|
||||
jdwpTransportCallback *callback,
|
||||
jint version,
|
||||
jdwpTransportEnv** env);
|
||||
|
||||
|
||||
|
||||
/* Function Interface */
|
||||
|
||||
struct jdwpTransportNativeInterface_ {
|
||||
/* 1 : RESERVED */
|
||||
void *reserved1;
|
||||
|
||||
/* 2 : Get Capabilities */
|
||||
jdwpTransportError (JNICALL *GetCapabilities)(jdwpTransportEnv* env,
|
||||
JDWPTransportCapabilities *capabilities_ptr);
|
||||
|
||||
/* 3 : Attach */
|
||||
jdwpTransportError (JNICALL *Attach)(jdwpTransportEnv* env,
|
||||
const char* address,
|
||||
jlong attach_timeout,
|
||||
jlong handshake_timeout);
|
||||
|
||||
/* 4: StartListening */
|
||||
jdwpTransportError (JNICALL *StartListening)(jdwpTransportEnv* env,
|
||||
const char* address,
|
||||
char** actual_address);
|
||||
|
||||
/* 5: StopListening */
|
||||
jdwpTransportError (JNICALL *StopListening)(jdwpTransportEnv* env);
|
||||
|
||||
/* 6: Accept */
|
||||
jdwpTransportError (JNICALL *Accept)(jdwpTransportEnv* env,
|
||||
jlong accept_timeout,
|
||||
jlong handshake_timeout);
|
||||
|
||||
/* 7: IsOpen */
|
||||
jboolean (JNICALL *IsOpen)(jdwpTransportEnv* env);
|
||||
|
||||
/* 8: Close */
|
||||
jdwpTransportError (JNICALL *Close)(jdwpTransportEnv* env);
|
||||
|
||||
/* 9: ReadPacket */
|
||||
jdwpTransportError (JNICALL *ReadPacket)(jdwpTransportEnv* env,
|
||||
jdwpPacket *pkt);
|
||||
|
||||
/* 10: Write Packet */
|
||||
jdwpTransportError (JNICALL *WritePacket)(jdwpTransportEnv* env,
|
||||
const jdwpPacket* pkt);
|
||||
|
||||
/* 11: GetLastError */
|
||||
jdwpTransportError (JNICALL *GetLastError)(jdwpTransportEnv* env,
|
||||
char** error);
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Use inlined functions so that C++ code can use syntax such as
|
||||
* env->Attach("mymachine:5000", 10*1000, 0);
|
||||
*
|
||||
* rather than using C's :-
|
||||
*
|
||||
* (*env)->Attach(env, "mymachine:5000", 10*1000, 0);
|
||||
*/
|
||||
struct _jdwpTransportEnv {
|
||||
const struct jdwpTransportNativeInterface_ *functions;
|
||||
#ifdef __cplusplus
|
||||
|
||||
jdwpTransportError GetCapabilities(JDWPTransportCapabilities *capabilities_ptr) {
|
||||
return functions->GetCapabilities(this, capabilities_ptr);
|
||||
}
|
||||
|
||||
jdwpTransportError Attach(const char* address, jlong attach_timeout,
|
||||
jlong handshake_timeout) {
|
||||
return functions->Attach(this, address, attach_timeout, handshake_timeout);
|
||||
}
|
||||
|
||||
jdwpTransportError StartListening(const char* address,
|
||||
char** actual_address) {
|
||||
return functions->StartListening(this, address, actual_address);
|
||||
}
|
||||
|
||||
jdwpTransportError StopListening(void) {
|
||||
return functions->StopListening(this);
|
||||
}
|
||||
|
||||
jdwpTransportError Accept(jlong accept_timeout, jlong handshake_timeout) {
|
||||
return functions->Accept(this, accept_timeout, handshake_timeout);
|
||||
}
|
||||
|
||||
jboolean IsOpen(void) {
|
||||
return functions->IsOpen(this);
|
||||
}
|
||||
|
||||
jdwpTransportError Close(void) {
|
||||
return functions->Close(this);
|
||||
}
|
||||
|
||||
jdwpTransportError ReadPacket(jdwpPacket *pkt) {
|
||||
return functions->ReadPacket(this, pkt);
|
||||
}
|
||||
|
||||
jdwpTransportError WritePacket(const jdwpPacket* pkt) {
|
||||
return functions->WritePacket(this, pkt);
|
||||
}
|
||||
|
||||
jdwpTransportError GetLastError(char** error) {
|
||||
return functions->GetLastError(this, error);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __cplusplus */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* JDWPTRANSPORT_H */
|
||||
|
||||
1944
cpp/wiiuse/include/jni.h
Normal file
1944
cpp/wiiuse/include/jni.h
Normal file
File diff suppressed because it is too large
Load Diff
2504
cpp/wiiuse/include/jvmti.h
Normal file
2504
cpp/wiiuse/include/jvmti.h
Normal file
File diff suppressed because it is too large
Load Diff
41
cpp/wiiuse/include/win32/jawt_md.h
Normal file
41
cpp/wiiuse/include/win32/jawt_md.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JAWT_MD_H_
|
||||
#define _JAVASOFT_JAWT_MD_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include "jawt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Win32-specific declarations for AWT native interface.
|
||||
* See notes in jawt.h for an example of use.
|
||||
*/
|
||||
typedef struct jawt_Win32DrawingSurfaceInfo {
|
||||
/* Native window, DDB, or DIB handle */
|
||||
union {
|
||||
HWND hwnd;
|
||||
HBITMAP hbitmap;
|
||||
void* pbits;
|
||||
};
|
||||
/*
|
||||
* This HDC should always be used instead of the HDC returned from
|
||||
* BeginPaint() or any calls to GetDC().
|
||||
*/
|
||||
HDC hdc;
|
||||
HPALETTE hpalette;
|
||||
} JAWT_Win32DrawingSurfaceInfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_JAVASOFT_JAWT_MD_H_ */
|
||||
19
cpp/wiiuse/include/win32/jni_md.h
Normal file
19
cpp/wiiuse/include/win32/jni_md.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JNI_MD_H_
|
||||
#define _JAVASOFT_JNI_MD_H_
|
||||
|
||||
#define JNIEXPORT __declspec(dllexport)
|
||||
#define JNIIMPORT __declspec(dllimport)
|
||||
#define JNICALL __stdcall
|
||||
|
||||
typedef long jint;
|
||||
typedef __int64 jlong;
|
||||
typedef signed char jbyte;
|
||||
|
||||
#endif /* !_JAVASOFT_JNI_MD_H_ */
|
||||
523
cpp/wiiusej/include/classfile_constants.h
Normal file
523
cpp/wiiusej/include/classfile_constants.h
Normal file
@@ -0,0 +1,523 @@
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CLASSFILE_CONSTANTS_H
|
||||
#define CLASSFILE_CONSTANTS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Flags */
|
||||
|
||||
enum {
|
||||
JVM_ACC_PUBLIC = 0x0001,
|
||||
JVM_ACC_PRIVATE = 0x0002,
|
||||
JVM_ACC_PROTECTED = 0x0004,
|
||||
JVM_ACC_STATIC = 0x0008,
|
||||
JVM_ACC_FINAL = 0x0010,
|
||||
JVM_ACC_SYNCHRONIZED = 0x0020,
|
||||
JVM_ACC_SUPER = 0x0020,
|
||||
JVM_ACC_VOLATILE = 0x0040,
|
||||
JVM_ACC_BRIDGE = 0x0040,
|
||||
JVM_ACC_TRANSIENT = 0x0080,
|
||||
JVM_ACC_VARARGS = 0x0080,
|
||||
JVM_ACC_NATIVE = 0x0100,
|
||||
JVM_ACC_INTERFACE = 0x0200,
|
||||
JVM_ACC_ABSTRACT = 0x0400,
|
||||
JVM_ACC_STRICT = 0x0800,
|
||||
JVM_ACC_SYNTHETIC = 0x1000,
|
||||
JVM_ACC_ANNOTATION = 0x2000,
|
||||
JVM_ACC_ENUM = 0x4000
|
||||
};
|
||||
|
||||
/* Used in newarray instruction. */
|
||||
|
||||
enum {
|
||||
JVM_T_BOOLEAN = 4,
|
||||
JVM_T_CHAR = 5,
|
||||
JVM_T_FLOAT = 6,
|
||||
JVM_T_DOUBLE = 7,
|
||||
JVM_T_BYTE = 8,
|
||||
JVM_T_SHORT = 9,
|
||||
JVM_T_INT = 10,
|
||||
JVM_T_LONG = 11
|
||||
};
|
||||
|
||||
/* Constant Pool Entries */
|
||||
|
||||
enum {
|
||||
JVM_CONSTANT_Utf8 = 1,
|
||||
JVM_CONSTANT_Unicode = 2, /* unused */
|
||||
JVM_CONSTANT_Integer = 3,
|
||||
JVM_CONSTANT_Float = 4,
|
||||
JVM_CONSTANT_Long = 5,
|
||||
JVM_CONSTANT_Double = 6,
|
||||
JVM_CONSTANT_Class = 7,
|
||||
JVM_CONSTANT_String = 8,
|
||||
JVM_CONSTANT_Fieldref = 9,
|
||||
JVM_CONSTANT_Methodref = 10,
|
||||
JVM_CONSTANT_InterfaceMethodref = 11,
|
||||
JVM_CONSTANT_NameAndType = 12
|
||||
};
|
||||
|
||||
/* StackMapTable type item numbers */
|
||||
|
||||
enum {
|
||||
JVM_ITEM_Top = 0,
|
||||
JVM_ITEM_Integer = 1,
|
||||
JVM_ITEM_Float = 2,
|
||||
JVM_ITEM_Double = 3,
|
||||
JVM_ITEM_Long = 4,
|
||||
JVM_ITEM_Null = 5,
|
||||
JVM_ITEM_UninitializedThis = 6,
|
||||
JVM_ITEM_Object = 7,
|
||||
JVM_ITEM_Uninitialized = 8
|
||||
};
|
||||
|
||||
/* Type signatures */
|
||||
|
||||
enum {
|
||||
JVM_SIGNATURE_ARRAY = '[',
|
||||
JVM_SIGNATURE_BYTE = 'B',
|
||||
JVM_SIGNATURE_CHAR = 'C',
|
||||
JVM_SIGNATURE_CLASS = 'L',
|
||||
JVM_SIGNATURE_ENDCLASS = ';',
|
||||
JVM_SIGNATURE_ENUM = 'E',
|
||||
JVM_SIGNATURE_FLOAT = 'F',
|
||||
JVM_SIGNATURE_DOUBLE = 'D',
|
||||
JVM_SIGNATURE_FUNC = '(',
|
||||
JVM_SIGNATURE_ENDFUNC = ')',
|
||||
JVM_SIGNATURE_INT = 'I',
|
||||
JVM_SIGNATURE_LONG = 'J',
|
||||
JVM_SIGNATURE_SHORT = 'S',
|
||||
JVM_SIGNATURE_VOID = 'V',
|
||||
JVM_SIGNATURE_BOOLEAN = 'Z'
|
||||
};
|
||||
|
||||
/* Opcodes */
|
||||
|
||||
enum {
|
||||
JVM_OPC_nop = 0,
|
||||
JVM_OPC_aconst_null = 1,
|
||||
JVM_OPC_iconst_m1 = 2,
|
||||
JVM_OPC_iconst_0 = 3,
|
||||
JVM_OPC_iconst_1 = 4,
|
||||
JVM_OPC_iconst_2 = 5,
|
||||
JVM_OPC_iconst_3 = 6,
|
||||
JVM_OPC_iconst_4 = 7,
|
||||
JVM_OPC_iconst_5 = 8,
|
||||
JVM_OPC_lconst_0 = 9,
|
||||
JVM_OPC_lconst_1 = 10,
|
||||
JVM_OPC_fconst_0 = 11,
|
||||
JVM_OPC_fconst_1 = 12,
|
||||
JVM_OPC_fconst_2 = 13,
|
||||
JVM_OPC_dconst_0 = 14,
|
||||
JVM_OPC_dconst_1 = 15,
|
||||
JVM_OPC_bipush = 16,
|
||||
JVM_OPC_sipush = 17,
|
||||
JVM_OPC_ldc = 18,
|
||||
JVM_OPC_ldc_w = 19,
|
||||
JVM_OPC_ldc2_w = 20,
|
||||
JVM_OPC_iload = 21,
|
||||
JVM_OPC_lload = 22,
|
||||
JVM_OPC_fload = 23,
|
||||
JVM_OPC_dload = 24,
|
||||
JVM_OPC_aload = 25,
|
||||
JVM_OPC_iload_0 = 26,
|
||||
JVM_OPC_iload_1 = 27,
|
||||
JVM_OPC_iload_2 = 28,
|
||||
JVM_OPC_iload_3 = 29,
|
||||
JVM_OPC_lload_0 = 30,
|
||||
JVM_OPC_lload_1 = 31,
|
||||
JVM_OPC_lload_2 = 32,
|
||||
JVM_OPC_lload_3 = 33,
|
||||
JVM_OPC_fload_0 = 34,
|
||||
JVM_OPC_fload_1 = 35,
|
||||
JVM_OPC_fload_2 = 36,
|
||||
JVM_OPC_fload_3 = 37,
|
||||
JVM_OPC_dload_0 = 38,
|
||||
JVM_OPC_dload_1 = 39,
|
||||
JVM_OPC_dload_2 = 40,
|
||||
JVM_OPC_dload_3 = 41,
|
||||
JVM_OPC_aload_0 = 42,
|
||||
JVM_OPC_aload_1 = 43,
|
||||
JVM_OPC_aload_2 = 44,
|
||||
JVM_OPC_aload_3 = 45,
|
||||
JVM_OPC_iaload = 46,
|
||||
JVM_OPC_laload = 47,
|
||||
JVM_OPC_faload = 48,
|
||||
JVM_OPC_daload = 49,
|
||||
JVM_OPC_aaload = 50,
|
||||
JVM_OPC_baload = 51,
|
||||
JVM_OPC_caload = 52,
|
||||
JVM_OPC_saload = 53,
|
||||
JVM_OPC_istore = 54,
|
||||
JVM_OPC_lstore = 55,
|
||||
JVM_OPC_fstore = 56,
|
||||
JVM_OPC_dstore = 57,
|
||||
JVM_OPC_astore = 58,
|
||||
JVM_OPC_istore_0 = 59,
|
||||
JVM_OPC_istore_1 = 60,
|
||||
JVM_OPC_istore_2 = 61,
|
||||
JVM_OPC_istore_3 = 62,
|
||||
JVM_OPC_lstore_0 = 63,
|
||||
JVM_OPC_lstore_1 = 64,
|
||||
JVM_OPC_lstore_2 = 65,
|
||||
JVM_OPC_lstore_3 = 66,
|
||||
JVM_OPC_fstore_0 = 67,
|
||||
JVM_OPC_fstore_1 = 68,
|
||||
JVM_OPC_fstore_2 = 69,
|
||||
JVM_OPC_fstore_3 = 70,
|
||||
JVM_OPC_dstore_0 = 71,
|
||||
JVM_OPC_dstore_1 = 72,
|
||||
JVM_OPC_dstore_2 = 73,
|
||||
JVM_OPC_dstore_3 = 74,
|
||||
JVM_OPC_astore_0 = 75,
|
||||
JVM_OPC_astore_1 = 76,
|
||||
JVM_OPC_astore_2 = 77,
|
||||
JVM_OPC_astore_3 = 78,
|
||||
JVM_OPC_iastore = 79,
|
||||
JVM_OPC_lastore = 80,
|
||||
JVM_OPC_fastore = 81,
|
||||
JVM_OPC_dastore = 82,
|
||||
JVM_OPC_aastore = 83,
|
||||
JVM_OPC_bastore = 84,
|
||||
JVM_OPC_castore = 85,
|
||||
JVM_OPC_sastore = 86,
|
||||
JVM_OPC_pop = 87,
|
||||
JVM_OPC_pop2 = 88,
|
||||
JVM_OPC_dup = 89,
|
||||
JVM_OPC_dup_x1 = 90,
|
||||
JVM_OPC_dup_x2 = 91,
|
||||
JVM_OPC_dup2 = 92,
|
||||
JVM_OPC_dup2_x1 = 93,
|
||||
JVM_OPC_dup2_x2 = 94,
|
||||
JVM_OPC_swap = 95,
|
||||
JVM_OPC_iadd = 96,
|
||||
JVM_OPC_ladd = 97,
|
||||
JVM_OPC_fadd = 98,
|
||||
JVM_OPC_dadd = 99,
|
||||
JVM_OPC_isub = 100,
|
||||
JVM_OPC_lsub = 101,
|
||||
JVM_OPC_fsub = 102,
|
||||
JVM_OPC_dsub = 103,
|
||||
JVM_OPC_imul = 104,
|
||||
JVM_OPC_lmul = 105,
|
||||
JVM_OPC_fmul = 106,
|
||||
JVM_OPC_dmul = 107,
|
||||
JVM_OPC_idiv = 108,
|
||||
JVM_OPC_ldiv = 109,
|
||||
JVM_OPC_fdiv = 110,
|
||||
JVM_OPC_ddiv = 111,
|
||||
JVM_OPC_irem = 112,
|
||||
JVM_OPC_lrem = 113,
|
||||
JVM_OPC_frem = 114,
|
||||
JVM_OPC_drem = 115,
|
||||
JVM_OPC_ineg = 116,
|
||||
JVM_OPC_lneg = 117,
|
||||
JVM_OPC_fneg = 118,
|
||||
JVM_OPC_dneg = 119,
|
||||
JVM_OPC_ishl = 120,
|
||||
JVM_OPC_lshl = 121,
|
||||
JVM_OPC_ishr = 122,
|
||||
JVM_OPC_lshr = 123,
|
||||
JVM_OPC_iushr = 124,
|
||||
JVM_OPC_lushr = 125,
|
||||
JVM_OPC_iand = 126,
|
||||
JVM_OPC_land = 127,
|
||||
JVM_OPC_ior = 128,
|
||||
JVM_OPC_lor = 129,
|
||||
JVM_OPC_ixor = 130,
|
||||
JVM_OPC_lxor = 131,
|
||||
JVM_OPC_iinc = 132,
|
||||
JVM_OPC_i2l = 133,
|
||||
JVM_OPC_i2f = 134,
|
||||
JVM_OPC_i2d = 135,
|
||||
JVM_OPC_l2i = 136,
|
||||
JVM_OPC_l2f = 137,
|
||||
JVM_OPC_l2d = 138,
|
||||
JVM_OPC_f2i = 139,
|
||||
JVM_OPC_f2l = 140,
|
||||
JVM_OPC_f2d = 141,
|
||||
JVM_OPC_d2i = 142,
|
||||
JVM_OPC_d2l = 143,
|
||||
JVM_OPC_d2f = 144,
|
||||
JVM_OPC_i2b = 145,
|
||||
JVM_OPC_i2c = 146,
|
||||
JVM_OPC_i2s = 147,
|
||||
JVM_OPC_lcmp = 148,
|
||||
JVM_OPC_fcmpl = 149,
|
||||
JVM_OPC_fcmpg = 150,
|
||||
JVM_OPC_dcmpl = 151,
|
||||
JVM_OPC_dcmpg = 152,
|
||||
JVM_OPC_ifeq = 153,
|
||||
JVM_OPC_ifne = 154,
|
||||
JVM_OPC_iflt = 155,
|
||||
JVM_OPC_ifge = 156,
|
||||
JVM_OPC_ifgt = 157,
|
||||
JVM_OPC_ifle = 158,
|
||||
JVM_OPC_if_icmpeq = 159,
|
||||
JVM_OPC_if_icmpne = 160,
|
||||
JVM_OPC_if_icmplt = 161,
|
||||
JVM_OPC_if_icmpge = 162,
|
||||
JVM_OPC_if_icmpgt = 163,
|
||||
JVM_OPC_if_icmple = 164,
|
||||
JVM_OPC_if_acmpeq = 165,
|
||||
JVM_OPC_if_acmpne = 166,
|
||||
JVM_OPC_goto = 167,
|
||||
JVM_OPC_jsr = 168,
|
||||
JVM_OPC_ret = 169,
|
||||
JVM_OPC_tableswitch = 170,
|
||||
JVM_OPC_lookupswitch = 171,
|
||||
JVM_OPC_ireturn = 172,
|
||||
JVM_OPC_lreturn = 173,
|
||||
JVM_OPC_freturn = 174,
|
||||
JVM_OPC_dreturn = 175,
|
||||
JVM_OPC_areturn = 176,
|
||||
JVM_OPC_return = 177,
|
||||
JVM_OPC_getstatic = 178,
|
||||
JVM_OPC_putstatic = 179,
|
||||
JVM_OPC_getfield = 180,
|
||||
JVM_OPC_putfield = 181,
|
||||
JVM_OPC_invokevirtual = 182,
|
||||
JVM_OPC_invokespecial = 183,
|
||||
JVM_OPC_invokestatic = 184,
|
||||
JVM_OPC_invokeinterface = 185,
|
||||
JVM_OPC_xxxunusedxxx = 186,
|
||||
JVM_OPC_new = 187,
|
||||
JVM_OPC_newarray = 188,
|
||||
JVM_OPC_anewarray = 189,
|
||||
JVM_OPC_arraylength = 190,
|
||||
JVM_OPC_athrow = 191,
|
||||
JVM_OPC_checkcast = 192,
|
||||
JVM_OPC_instanceof = 193,
|
||||
JVM_OPC_monitorenter = 194,
|
||||
JVM_OPC_monitorexit = 195,
|
||||
JVM_OPC_wide = 196,
|
||||
JVM_OPC_multianewarray = 197,
|
||||
JVM_OPC_ifnull = 198,
|
||||
JVM_OPC_ifnonnull = 199,
|
||||
JVM_OPC_goto_w = 200,
|
||||
JVM_OPC_jsr_w = 201,
|
||||
JVM_OPC_MAX = 201
|
||||
};
|
||||
|
||||
/* Opcode length initializer, use with something like:
|
||||
* unsigned char opcode_length[JVM_OPC_MAX+1] = JVM_OPCODE_LENGTH_INITIALIZER;
|
||||
*/
|
||||
#define JVM_OPCODE_LENGTH_INITIALIZER { \
|
||||
1, /* nop */ \
|
||||
1, /* aconst_null */ \
|
||||
1, /* iconst_m1 */ \
|
||||
1, /* iconst_0 */ \
|
||||
1, /* iconst_1 */ \
|
||||
1, /* iconst_2 */ \
|
||||
1, /* iconst_3 */ \
|
||||
1, /* iconst_4 */ \
|
||||
1, /* iconst_5 */ \
|
||||
1, /* lconst_0 */ \
|
||||
1, /* lconst_1 */ \
|
||||
1, /* fconst_0 */ \
|
||||
1, /* fconst_1 */ \
|
||||
1, /* fconst_2 */ \
|
||||
1, /* dconst_0 */ \
|
||||
1, /* dconst_1 */ \
|
||||
2, /* bipush */ \
|
||||
3, /* sipush */ \
|
||||
2, /* ldc */ \
|
||||
3, /* ldc_w */ \
|
||||
3, /* ldc2_w */ \
|
||||
2, /* iload */ \
|
||||
2, /* lload */ \
|
||||
2, /* fload */ \
|
||||
2, /* dload */ \
|
||||
2, /* aload */ \
|
||||
1, /* iload_0 */ \
|
||||
1, /* iload_1 */ \
|
||||
1, /* iload_2 */ \
|
||||
1, /* iload_3 */ \
|
||||
1, /* lload_0 */ \
|
||||
1, /* lload_1 */ \
|
||||
1, /* lload_2 */ \
|
||||
1, /* lload_3 */ \
|
||||
1, /* fload_0 */ \
|
||||
1, /* fload_1 */ \
|
||||
1, /* fload_2 */ \
|
||||
1, /* fload_3 */ \
|
||||
1, /* dload_0 */ \
|
||||
1, /* dload_1 */ \
|
||||
1, /* dload_2 */ \
|
||||
1, /* dload_3 */ \
|
||||
1, /* aload_0 */ \
|
||||
1, /* aload_1 */ \
|
||||
1, /* aload_2 */ \
|
||||
1, /* aload_3 */ \
|
||||
1, /* iaload */ \
|
||||
1, /* laload */ \
|
||||
1, /* faload */ \
|
||||
1, /* daload */ \
|
||||
1, /* aaload */ \
|
||||
1, /* baload */ \
|
||||
1, /* caload */ \
|
||||
1, /* saload */ \
|
||||
2, /* istore */ \
|
||||
2, /* lstore */ \
|
||||
2, /* fstore */ \
|
||||
2, /* dstore */ \
|
||||
2, /* astore */ \
|
||||
1, /* istore_0 */ \
|
||||
1, /* istore_1 */ \
|
||||
1, /* istore_2 */ \
|
||||
1, /* istore_3 */ \
|
||||
1, /* lstore_0 */ \
|
||||
1, /* lstore_1 */ \
|
||||
1, /* lstore_2 */ \
|
||||
1, /* lstore_3 */ \
|
||||
1, /* fstore_0 */ \
|
||||
1, /* fstore_1 */ \
|
||||
1, /* fstore_2 */ \
|
||||
1, /* fstore_3 */ \
|
||||
1, /* dstore_0 */ \
|
||||
1, /* dstore_1 */ \
|
||||
1, /* dstore_2 */ \
|
||||
1, /* dstore_3 */ \
|
||||
1, /* astore_0 */ \
|
||||
1, /* astore_1 */ \
|
||||
1, /* astore_2 */ \
|
||||
1, /* astore_3 */ \
|
||||
1, /* iastore */ \
|
||||
1, /* lastore */ \
|
||||
1, /* fastore */ \
|
||||
1, /* dastore */ \
|
||||
1, /* aastore */ \
|
||||
1, /* bastore */ \
|
||||
1, /* castore */ \
|
||||
1, /* sastore */ \
|
||||
1, /* pop */ \
|
||||
1, /* pop2 */ \
|
||||
1, /* dup */ \
|
||||
1, /* dup_x1 */ \
|
||||
1, /* dup_x2 */ \
|
||||
1, /* dup2 */ \
|
||||
1, /* dup2_x1 */ \
|
||||
1, /* dup2_x2 */ \
|
||||
1, /* swap */ \
|
||||
1, /* iadd */ \
|
||||
1, /* ladd */ \
|
||||
1, /* fadd */ \
|
||||
1, /* dadd */ \
|
||||
1, /* isub */ \
|
||||
1, /* lsub */ \
|
||||
1, /* fsub */ \
|
||||
1, /* dsub */ \
|
||||
1, /* imul */ \
|
||||
1, /* lmul */ \
|
||||
1, /* fmul */ \
|
||||
1, /* dmul */ \
|
||||
1, /* idiv */ \
|
||||
1, /* ldiv */ \
|
||||
1, /* fdiv */ \
|
||||
1, /* ddiv */ \
|
||||
1, /* irem */ \
|
||||
1, /* lrem */ \
|
||||
1, /* frem */ \
|
||||
1, /* drem */ \
|
||||
1, /* ineg */ \
|
||||
1, /* lneg */ \
|
||||
1, /* fneg */ \
|
||||
1, /* dneg */ \
|
||||
1, /* ishl */ \
|
||||
1, /* lshl */ \
|
||||
1, /* ishr */ \
|
||||
1, /* lshr */ \
|
||||
1, /* iushr */ \
|
||||
1, /* lushr */ \
|
||||
1, /* iand */ \
|
||||
1, /* land */ \
|
||||
1, /* ior */ \
|
||||
1, /* lor */ \
|
||||
1, /* ixor */ \
|
||||
1, /* lxor */ \
|
||||
3, /* iinc */ \
|
||||
1, /* i2l */ \
|
||||
1, /* i2f */ \
|
||||
1, /* i2d */ \
|
||||
1, /* l2i */ \
|
||||
1, /* l2f */ \
|
||||
1, /* l2d */ \
|
||||
1, /* f2i */ \
|
||||
1, /* f2l */ \
|
||||
1, /* f2d */ \
|
||||
1, /* d2i */ \
|
||||
1, /* d2l */ \
|
||||
1, /* d2f */ \
|
||||
1, /* i2b */ \
|
||||
1, /* i2c */ \
|
||||
1, /* i2s */ \
|
||||
1, /* lcmp */ \
|
||||
1, /* fcmpl */ \
|
||||
1, /* fcmpg */ \
|
||||
1, /* dcmpl */ \
|
||||
1, /* dcmpg */ \
|
||||
3, /* ifeq */ \
|
||||
3, /* ifne */ \
|
||||
3, /* iflt */ \
|
||||
3, /* ifge */ \
|
||||
3, /* ifgt */ \
|
||||
3, /* ifle */ \
|
||||
3, /* if_icmpeq */ \
|
||||
3, /* if_icmpne */ \
|
||||
3, /* if_icmplt */ \
|
||||
3, /* if_icmpge */ \
|
||||
3, /* if_icmpgt */ \
|
||||
3, /* if_icmple */ \
|
||||
3, /* if_acmpeq */ \
|
||||
3, /* if_acmpne */ \
|
||||
3, /* goto */ \
|
||||
3, /* jsr */ \
|
||||
2, /* ret */ \
|
||||
99, /* tableswitch */ \
|
||||
99, /* lookupswitch */ \
|
||||
1, /* ireturn */ \
|
||||
1, /* lreturn */ \
|
||||
1, /* freturn */ \
|
||||
1, /* dreturn */ \
|
||||
1, /* areturn */ \
|
||||
1, /* return */ \
|
||||
3, /* getstatic */ \
|
||||
3, /* putstatic */ \
|
||||
3, /* getfield */ \
|
||||
3, /* putfield */ \
|
||||
3, /* invokevirtual */ \
|
||||
3, /* invokespecial */ \
|
||||
3, /* invokestatic */ \
|
||||
5, /* invokeinterface */ \
|
||||
0, /* xxxunusedxxx */ \
|
||||
3, /* new */ \
|
||||
2, /* newarray */ \
|
||||
3, /* anewarray */ \
|
||||
1, /* arraylength */ \
|
||||
1, /* athrow */ \
|
||||
3, /* checkcast */ \
|
||||
3, /* instanceof */ \
|
||||
1, /* monitorenter */ \
|
||||
1, /* monitorexit */ \
|
||||
0, /* wide */ \
|
||||
4, /* multianewarray */ \
|
||||
3, /* ifnull */ \
|
||||
3, /* ifnonnull */ \
|
||||
5, /* goto_w */ \
|
||||
5 /* jsr_w */ \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* CLASSFILE_CONSTANTS */
|
||||
278
cpp/wiiusej/include/jawt.h
Normal file
278
cpp/wiiusej/include/jawt.h
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JAWT_H_
|
||||
#define _JAVASOFT_JAWT_H_
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AWT native interface (new in JDK 1.3)
|
||||
*
|
||||
* The AWT native interface allows a native C or C++ application a means
|
||||
* by which to access native structures in AWT. This is to facilitate moving
|
||||
* legacy C and C++ applications to Java and to target the needs of the
|
||||
* community who, at present, wish to do their own native rendering to canvases
|
||||
* for performance reasons. Standard extensions such as Java3D also require a
|
||||
* means to access the underlying native data structures of AWT.
|
||||
*
|
||||
* There may be future extensions to this API depending on demand.
|
||||
*
|
||||
* A VM does not have to implement this API in order to pass the JCK.
|
||||
* It is recommended, however, that this API is implemented on VMs that support
|
||||
* standard extensions, such as Java3D.
|
||||
*
|
||||
* Since this is a native API, any program which uses it cannot be considered
|
||||
* 100% pure java.
|
||||
*/
|
||||
|
||||
/*
|
||||
* AWT Native Drawing Surface (JAWT_DrawingSurface).
|
||||
*
|
||||
* For each platform, there is a native drawing surface structure. This
|
||||
* platform-specific structure can be found in jawt_md.h. It is recommended
|
||||
* that additional platforms follow the same model. It is also recommended
|
||||
* that VMs on Win32 and Solaris support the existing structures in jawt_md.h.
|
||||
*
|
||||
*******************
|
||||
* EXAMPLE OF USAGE:
|
||||
*******************
|
||||
*
|
||||
* In Win32, a programmer wishes to access the HWND of a canvas to perform
|
||||
* native rendering into it. The programmer has declared the paint() method
|
||||
* for their canvas subclass to be native:
|
||||
*
|
||||
*
|
||||
* MyCanvas.java:
|
||||
*
|
||||
* import java.awt.*;
|
||||
*
|
||||
* public class MyCanvas extends Canvas {
|
||||
*
|
||||
* static {
|
||||
* System.loadLibrary("mylib");
|
||||
* }
|
||||
*
|
||||
* public native void paint(Graphics g);
|
||||
* }
|
||||
*
|
||||
*
|
||||
* myfile.c:
|
||||
*
|
||||
* #include "jawt_md.h"
|
||||
* #include <assert.h>
|
||||
*
|
||||
* JNIEXPORT void JNICALL
|
||||
* Java_MyCanvas_paint(JNIEnv* env, jobject canvas, jobject graphics)
|
||||
* {
|
||||
* JAWT awt;
|
||||
* JAWT_DrawingSurface* ds;
|
||||
* JAWT_DrawingSurfaceInfo* dsi;
|
||||
* JAWT_Win32DrawingSurfaceInfo* dsi_win;
|
||||
* jboolean result;
|
||||
* jint lock;
|
||||
*
|
||||
* // Get the AWT
|
||||
* awt.version = JAWT_VERSION_1_3;
|
||||
* result = JAWT_GetAWT(env, &awt);
|
||||
* assert(result != JNI_FALSE);
|
||||
*
|
||||
* // Get the drawing surface
|
||||
* ds = awt.GetDrawingSurface(env, canvas);
|
||||
* assert(ds != NULL);
|
||||
*
|
||||
* // Lock the drawing surface
|
||||
* lock = ds->Lock(ds);
|
||||
* assert((lock & JAWT_LOCK_ERROR) == 0);
|
||||
*
|
||||
* // Get the drawing surface info
|
||||
* dsi = ds->GetDrawingSurfaceInfo(ds);
|
||||
*
|
||||
* // Get the platform-specific drawing info
|
||||
* dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
|
||||
*
|
||||
* //////////////////////////////
|
||||
* // !!! DO PAINTING HERE !!! //
|
||||
* //////////////////////////////
|
||||
*
|
||||
* // Free the drawing surface info
|
||||
* ds->FreeDrawingSurfaceInfo(dsi);
|
||||
*
|
||||
* // Unlock the drawing surface
|
||||
* ds->Unlock(ds);
|
||||
*
|
||||
* // Free the drawing surface
|
||||
* awt.FreeDrawingSurface(ds);
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* JAWT_Rectangle
|
||||
* Structure for a native rectangle.
|
||||
*/
|
||||
typedef struct jawt_Rectangle {
|
||||
jint x;
|
||||
jint y;
|
||||
jint width;
|
||||
jint height;
|
||||
} JAWT_Rectangle;
|
||||
|
||||
struct jawt_DrawingSurface;
|
||||
|
||||
/*
|
||||
* JAWT_DrawingSurfaceInfo
|
||||
* Structure for containing the underlying drawing information of a component.
|
||||
*/
|
||||
typedef struct jawt_DrawingSurfaceInfo {
|
||||
/*
|
||||
* Pointer to the platform-specific information. This can be safely
|
||||
* cast to a JAWT_Win32DrawingSurfaceInfo on Windows or a
|
||||
* JAWT_X11DrawingSurfaceInfo on Solaris. See jawt_md.h for details.
|
||||
*/
|
||||
void* platformInfo;
|
||||
/* Cached pointer to the underlying drawing surface */
|
||||
struct jawt_DrawingSurface* ds;
|
||||
/* Bounding rectangle of the drawing surface */
|
||||
JAWT_Rectangle bounds;
|
||||
/* Number of rectangles in the clip */
|
||||
jint clipSize;
|
||||
/* Clip rectangle array */
|
||||
JAWT_Rectangle* clip;
|
||||
} JAWT_DrawingSurfaceInfo;
|
||||
|
||||
#define JAWT_LOCK_ERROR 0x00000001
|
||||
#define JAWT_LOCK_CLIP_CHANGED 0x00000002
|
||||
#define JAWT_LOCK_BOUNDS_CHANGED 0x00000004
|
||||
#define JAWT_LOCK_SURFACE_CHANGED 0x00000008
|
||||
|
||||
/*
|
||||
* JAWT_DrawingSurface
|
||||
* Structure for containing the underlying drawing information of a component.
|
||||
* All operations on a JAWT_DrawingSurface MUST be performed from the same
|
||||
* thread as the call to GetDrawingSurface.
|
||||
*/
|
||||
typedef struct jawt_DrawingSurface {
|
||||
/*
|
||||
* Cached reference to the Java environment of the calling thread.
|
||||
* If Lock(), Unlock(), GetDrawingSurfaceInfo() or
|
||||
* FreeDrawingSurfaceInfo() are called from a different thread,
|
||||
* this data member should be set before calling those functions.
|
||||
*/
|
||||
JNIEnv* env;
|
||||
/* Cached reference to the target object */
|
||||
jobject target;
|
||||
/*
|
||||
* Lock the surface of the target component for native rendering.
|
||||
* When finished drawing, the surface must be unlocked with
|
||||
* Unlock(). This function returns a bitmask with one or more of the
|
||||
* following values:
|
||||
*
|
||||
* JAWT_LOCK_ERROR - When an error has occurred and the surface could not
|
||||
* be locked.
|
||||
*
|
||||
* JAWT_LOCK_CLIP_CHANGED - When the clip region has changed.
|
||||
*
|
||||
* JAWT_LOCK_BOUNDS_CHANGED - When the bounds of the surface have changed.
|
||||
*
|
||||
* JAWT_LOCK_SURFACE_CHANGED - When the surface itself has changed
|
||||
*/
|
||||
jint (JNICALL *Lock)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
/*
|
||||
* Get the drawing surface info.
|
||||
* The value returned may be cached, but the values may change if
|
||||
* additional calls to Lock() or Unlock() are made.
|
||||
* Lock() must be called before this can return a valid value.
|
||||
* Returns NULL if an error has occurred.
|
||||
* When finished with the returned value, FreeDrawingSurfaceInfo must be
|
||||
* called.
|
||||
*/
|
||||
JAWT_DrawingSurfaceInfo* (JNICALL *GetDrawingSurfaceInfo)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
/*
|
||||
* Free the drawing surface info.
|
||||
*/
|
||||
void (JNICALL *FreeDrawingSurfaceInfo)
|
||||
(JAWT_DrawingSurfaceInfo* dsi);
|
||||
/*
|
||||
* Unlock the drawing surface of the target component for native rendering.
|
||||
*/
|
||||
void (JNICALL *Unlock)
|
||||
(struct jawt_DrawingSurface* ds);
|
||||
} JAWT_DrawingSurface;
|
||||
|
||||
/*
|
||||
* JAWT
|
||||
* Structure for containing native AWT functions.
|
||||
*/
|
||||
typedef struct jawt {
|
||||
/*
|
||||
* Version of this structure. This must always be set before
|
||||
* calling JAWT_GetAWT()
|
||||
*/
|
||||
jint version;
|
||||
/*
|
||||
* Return a drawing surface from a target jobject. This value
|
||||
* may be cached.
|
||||
* Returns NULL if an error has occurred.
|
||||
* Target must be a java.awt.Component (should be a Canvas
|
||||
* or Window for native rendering).
|
||||
* FreeDrawingSurface() must be called when finished with the
|
||||
* returned JAWT_DrawingSurface.
|
||||
*/
|
||||
JAWT_DrawingSurface* (JNICALL *GetDrawingSurface)
|
||||
(JNIEnv* env, jobject target);
|
||||
/*
|
||||
* Free the drawing surface allocated in GetDrawingSurface.
|
||||
*/
|
||||
void (JNICALL *FreeDrawingSurface)
|
||||
(JAWT_DrawingSurface* ds);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Locks the entire AWT for synchronization purposes
|
||||
*/
|
||||
void (JNICALL *Lock)(JNIEnv* env);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Unlocks the entire AWT for synchronization purposes
|
||||
*/
|
||||
void (JNICALL *Unlock)(JNIEnv* env);
|
||||
/*
|
||||
* Since 1.4
|
||||
* Returns a reference to a java.awt.Component from a native
|
||||
* platform handle. On Windows, this corresponds to an HWND;
|
||||
* on Solaris and Linux, this is a Drawable. For other platforms,
|
||||
* see the appropriate machine-dependent header file for a description.
|
||||
* The reference returned by this function is a local
|
||||
* reference that is only valid in this environment.
|
||||
* This function returns a NULL reference if no component could be
|
||||
* found with matching platform information.
|
||||
*/
|
||||
jobject (JNICALL *GetComponent)(JNIEnv* env, void* platformInfo);
|
||||
|
||||
} JAWT;
|
||||
|
||||
/*
|
||||
* Get the AWT native structure. This function returns JNI_FALSE if
|
||||
* an error occurs.
|
||||
*/
|
||||
_JNI_IMPORT_OR_EXPORT_
|
||||
jboolean JNICALL JAWT_GetAWT(JNIEnv* env, JAWT* awt);
|
||||
|
||||
#define JAWT_VERSION_1_3 0x00010003
|
||||
#define JAWT_VERSION_1_4 0x00010004
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* !_JAVASOFT_JAWT_H_ */
|
||||
237
cpp/wiiusej/include/jdwpTransport.h
Normal file
237
cpp/wiiusej/include/jdwpTransport.h
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Java Debug Wire Protocol Transport Service Provider Interface.
|
||||
*/
|
||||
|
||||
#ifndef JDWPTRANSPORT_H
|
||||
#define JDWPTRANSPORT_H
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
enum {
|
||||
JDWPTRANSPORT_VERSION_1_0 = 0x00010000
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct jdwpTransportNativeInterface_;
|
||||
|
||||
struct _jdwpTransportEnv;
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef _jdwpTransportEnv jdwpTransportEnv;
|
||||
#else
|
||||
typedef const struct jdwpTransportNativeInterface_ *jdwpTransportEnv;
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* Errors. Universal errors with JVMTI/JVMDI equivalents keep the
|
||||
* values the same.
|
||||
*/
|
||||
typedef enum {
|
||||
JDWPTRANSPORT_ERROR_NONE = 0,
|
||||
JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT = 103,
|
||||
JDWPTRANSPORT_ERROR_OUT_OF_MEMORY = 110,
|
||||
JDWPTRANSPORT_ERROR_INTERNAL = 113,
|
||||
JDWPTRANSPORT_ERROR_ILLEGAL_STATE = 201,
|
||||
JDWPTRANSPORT_ERROR_IO_ERROR = 202,
|
||||
JDWPTRANSPORT_ERROR_TIMEOUT = 203,
|
||||
JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE = 204
|
||||
} jdwpTransportError;
|
||||
|
||||
|
||||
/*
|
||||
* Structure to define capabilities
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int can_timeout_attach :1;
|
||||
unsigned int can_timeout_accept :1;
|
||||
unsigned int can_timeout_handshake :1;
|
||||
unsigned int reserved3 :1;
|
||||
unsigned int reserved4 :1;
|
||||
unsigned int reserved5 :1;
|
||||
unsigned int reserved6 :1;
|
||||
unsigned int reserved7 :1;
|
||||
unsigned int reserved8 :1;
|
||||
unsigned int reserved9 :1;
|
||||
unsigned int reserved10 :1;
|
||||
unsigned int reserved11 :1;
|
||||
unsigned int reserved12 :1;
|
||||
unsigned int reserved13 :1;
|
||||
unsigned int reserved14 :1;
|
||||
unsigned int reserved15 :1;
|
||||
} JDWPTransportCapabilities;
|
||||
|
||||
|
||||
/*
|
||||
* Structures to define packet layout.
|
||||
*
|
||||
* See: http://java.sun.com/j2se/1.5/docs/guide/jpda/jdwp-spec.html
|
||||
*/
|
||||
|
||||
enum {
|
||||
JDWPTRANSPORT_FLAGS_NONE = 0x0,
|
||||
JDWPTRANSPORT_FLAGS_REPLY = 0x80
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
jint len;
|
||||
jint id;
|
||||
jbyte flags;
|
||||
jbyte cmdSet;
|
||||
jbyte cmd;
|
||||
jbyte *data;
|
||||
} jdwpCmdPacket;
|
||||
|
||||
typedef struct {
|
||||
jint len;
|
||||
jint id;
|
||||
jbyte flags;
|
||||
jshort errorCode;
|
||||
jbyte *data;
|
||||
} jdwpReplyPacket;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
jdwpCmdPacket cmd;
|
||||
jdwpReplyPacket reply;
|
||||
} type;
|
||||
} jdwpPacket;
|
||||
|
||||
/*
|
||||
* JDWP functions called by the transport.
|
||||
*/
|
||||
typedef struct jdwpTransportCallback {
|
||||
void *(*alloc)(jint numBytes); /* Call this for all allocations */
|
||||
void (*free)(void *buffer); /* Call this for all deallocations */
|
||||
} jdwpTransportCallback;
|
||||
|
||||
typedef jint (JNICALL *jdwpTransport_OnLoad_t)(JavaVM *jvm,
|
||||
jdwpTransportCallback *callback,
|
||||
jint version,
|
||||
jdwpTransportEnv** env);
|
||||
|
||||
|
||||
|
||||
/* Function Interface */
|
||||
|
||||
struct jdwpTransportNativeInterface_ {
|
||||
/* 1 : RESERVED */
|
||||
void *reserved1;
|
||||
|
||||
/* 2 : Get Capabilities */
|
||||
jdwpTransportError (JNICALL *GetCapabilities)(jdwpTransportEnv* env,
|
||||
JDWPTransportCapabilities *capabilities_ptr);
|
||||
|
||||
/* 3 : Attach */
|
||||
jdwpTransportError (JNICALL *Attach)(jdwpTransportEnv* env,
|
||||
const char* address,
|
||||
jlong attach_timeout,
|
||||
jlong handshake_timeout);
|
||||
|
||||
/* 4: StartListening */
|
||||
jdwpTransportError (JNICALL *StartListening)(jdwpTransportEnv* env,
|
||||
const char* address,
|
||||
char** actual_address);
|
||||
|
||||
/* 5: StopListening */
|
||||
jdwpTransportError (JNICALL *StopListening)(jdwpTransportEnv* env);
|
||||
|
||||
/* 6: Accept */
|
||||
jdwpTransportError (JNICALL *Accept)(jdwpTransportEnv* env,
|
||||
jlong accept_timeout,
|
||||
jlong handshake_timeout);
|
||||
|
||||
/* 7: IsOpen */
|
||||
jboolean (JNICALL *IsOpen)(jdwpTransportEnv* env);
|
||||
|
||||
/* 8: Close */
|
||||
jdwpTransportError (JNICALL *Close)(jdwpTransportEnv* env);
|
||||
|
||||
/* 9: ReadPacket */
|
||||
jdwpTransportError (JNICALL *ReadPacket)(jdwpTransportEnv* env,
|
||||
jdwpPacket *pkt);
|
||||
|
||||
/* 10: Write Packet */
|
||||
jdwpTransportError (JNICALL *WritePacket)(jdwpTransportEnv* env,
|
||||
const jdwpPacket* pkt);
|
||||
|
||||
/* 11: GetLastError */
|
||||
jdwpTransportError (JNICALL *GetLastError)(jdwpTransportEnv* env,
|
||||
char** error);
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Use inlined functions so that C++ code can use syntax such as
|
||||
* env->Attach("mymachine:5000", 10*1000, 0);
|
||||
*
|
||||
* rather than using C's :-
|
||||
*
|
||||
* (*env)->Attach(env, "mymachine:5000", 10*1000, 0);
|
||||
*/
|
||||
struct _jdwpTransportEnv {
|
||||
const struct jdwpTransportNativeInterface_ *functions;
|
||||
#ifdef __cplusplus
|
||||
|
||||
jdwpTransportError GetCapabilities(JDWPTransportCapabilities *capabilities_ptr) {
|
||||
return functions->GetCapabilities(this, capabilities_ptr);
|
||||
}
|
||||
|
||||
jdwpTransportError Attach(const char* address, jlong attach_timeout,
|
||||
jlong handshake_timeout) {
|
||||
return functions->Attach(this, address, attach_timeout, handshake_timeout);
|
||||
}
|
||||
|
||||
jdwpTransportError StartListening(const char* address,
|
||||
char** actual_address) {
|
||||
return functions->StartListening(this, address, actual_address);
|
||||
}
|
||||
|
||||
jdwpTransportError StopListening(void) {
|
||||
return functions->StopListening(this);
|
||||
}
|
||||
|
||||
jdwpTransportError Accept(jlong accept_timeout, jlong handshake_timeout) {
|
||||
return functions->Accept(this, accept_timeout, handshake_timeout);
|
||||
}
|
||||
|
||||
jboolean IsOpen(void) {
|
||||
return functions->IsOpen(this);
|
||||
}
|
||||
|
||||
jdwpTransportError Close(void) {
|
||||
return functions->Close(this);
|
||||
}
|
||||
|
||||
jdwpTransportError ReadPacket(jdwpPacket *pkt) {
|
||||
return functions->ReadPacket(this, pkt);
|
||||
}
|
||||
|
||||
jdwpTransportError WritePacket(const jdwpPacket* pkt) {
|
||||
return functions->WritePacket(this, pkt);
|
||||
}
|
||||
|
||||
jdwpTransportError GetLastError(char** error) {
|
||||
return functions->GetLastError(this, error);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __cplusplus */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* JDWPTRANSPORT_H */
|
||||
|
||||
1944
cpp/wiiusej/include/jni.h
Normal file
1944
cpp/wiiusej/include/jni.h
Normal file
File diff suppressed because it is too large
Load Diff
2504
cpp/wiiusej/include/jvmti.h
Normal file
2504
cpp/wiiusej/include/jvmti.h
Normal file
File diff suppressed because it is too large
Load Diff
41
cpp/wiiusej/include/win32/jawt_md.h
Normal file
41
cpp/wiiusej/include/win32/jawt_md.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JAWT_MD_H_
|
||||
#define _JAVASOFT_JAWT_MD_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include "jawt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Win32-specific declarations for AWT native interface.
|
||||
* See notes in jawt.h for an example of use.
|
||||
*/
|
||||
typedef struct jawt_Win32DrawingSurfaceInfo {
|
||||
/* Native window, DDB, or DIB handle */
|
||||
union {
|
||||
HWND hwnd;
|
||||
HBITMAP hbitmap;
|
||||
void* pbits;
|
||||
};
|
||||
/*
|
||||
* This HDC should always be used instead of the HDC returned from
|
||||
* BeginPaint() or any calls to GetDC().
|
||||
*/
|
||||
HDC hdc;
|
||||
HPALETTE hpalette;
|
||||
} JAWT_Win32DrawingSurfaceInfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_JAVASOFT_JAWT_MD_H_ */
|
||||
19
cpp/wiiusej/include/win32/jni_md.h
Normal file
19
cpp/wiiusej/include/win32/jni_md.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _JAVASOFT_JNI_MD_H_
|
||||
#define _JAVASOFT_JNI_MD_H_
|
||||
|
||||
#define JNIEXPORT __declspec(dllexport)
|
||||
#define JNIIMPORT __declspec(dllimport)
|
||||
#define JNICALL __stdcall
|
||||
|
||||
typedef long jint;
|
||||
typedef __int64 jlong;
|
||||
typedef signed char jbyte;
|
||||
|
||||
#endif /* !_JAVASOFT_JNI_MD_H_ */
|
||||
Binary file not shown.
@@ -44,7 +44,7 @@
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>C:\Program Files (x86)\Java\jdk1.6.0_23\include;C:\Program Files (x86)\Java\jdk1.6.0_23\include\win32;$(IncludePath)</IncludePath>
|
||||
<IncludePath>..\include;..\include\win32;$(IncludePath)</IncludePath>
|
||||
<OutDir>.\Release\</OutDir>
|
||||
<ExtensionsToDeleteOnClean>$(ExtensionsToDeleteOnClean)</ExtensionsToDeleteOnClean>
|
||||
<LibraryPath>..\lib;$(LibraryPath)</LibraryPath>
|
||||
|
||||
Binary file not shown.
142
java/src/org/apache/log4j/Appender.java
Normal file
142
java/src/org/apache/log4j/Appender.java
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.Filter;
|
||||
import org.apache.log4j.spi.ErrorHandler;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
Implement this interface for your own strategies for outputting log
|
||||
statements.
|
||||
|
||||
@author Ceki Gülcü
|
||||
*/
|
||||
public interface Appender {
|
||||
|
||||
/**
|
||||
Add a filter to the end of the filter list.
|
||||
|
||||
@since 0.9.0
|
||||
*/
|
||||
void addFilter(Filter newFilter);
|
||||
|
||||
/**
|
||||
Returns the head Filter. The Filters are organized in a linked list
|
||||
and so all Filters on this Appender are available through the result.
|
||||
|
||||
@return the head Filter or null, if no Filters are present
|
||||
@since 1.1
|
||||
*/
|
||||
public
|
||||
Filter getFilter();
|
||||
|
||||
/**
|
||||
Clear the list of filters by removing all the filters in it.
|
||||
|
||||
@since 0.9.0
|
||||
*/
|
||||
public
|
||||
void clearFilters();
|
||||
|
||||
/**
|
||||
Release any resources allocated within the appender such as file
|
||||
handles, network connections, etc.
|
||||
|
||||
<p>It is a programming error to append to a closed appender.
|
||||
|
||||
@since 0.8.4
|
||||
*/
|
||||
public
|
||||
void close();
|
||||
|
||||
/**
|
||||
Log in <code>Appender</code> specific way. When appropriate,
|
||||
Loggers will call the <code>doAppend</code> method of appender
|
||||
implementations in order to log. */
|
||||
public
|
||||
void doAppend(LoggingEvent event);
|
||||
|
||||
|
||||
/**
|
||||
Get the name of this appender.
|
||||
@return name, may be null.*/
|
||||
public
|
||||
String getName();
|
||||
|
||||
|
||||
/**
|
||||
Set the {@link ErrorHandler} for this appender.
|
||||
|
||||
@since 0.9.0
|
||||
*/
|
||||
public
|
||||
void setErrorHandler(ErrorHandler errorHandler);
|
||||
|
||||
/**
|
||||
Returns the {@link ErrorHandler} for this appender.
|
||||
|
||||
@since 1.1
|
||||
*/
|
||||
public
|
||||
ErrorHandler getErrorHandler();
|
||||
|
||||
/**
|
||||
Set the {@link Layout} for this appender.
|
||||
|
||||
@since 0.8.1
|
||||
*/
|
||||
public
|
||||
void setLayout(Layout layout);
|
||||
|
||||
/**
|
||||
Returns this appenders layout.
|
||||
|
||||
@since 1.1
|
||||
*/
|
||||
public
|
||||
Layout getLayout();
|
||||
|
||||
|
||||
/**
|
||||
Set the name of this appender. The name is used by other
|
||||
components to identify this appender.
|
||||
|
||||
@since 0.8.1
|
||||
*/
|
||||
public
|
||||
void setName(String name);
|
||||
|
||||
/**
|
||||
Configurators call this method to determine if the appender
|
||||
requires a layout. If this method returns <code>true</code>,
|
||||
meaning that layout is required, then the configurator will
|
||||
configure an layout using the configuration information at its
|
||||
disposal. If this method returns <code>false</code>, meaning that
|
||||
a layout is not required, then layout configuration will be
|
||||
skipped even if there is available layout configuration
|
||||
information at the disposal of the configurator..
|
||||
|
||||
<p>In the rather exceptional case, where the appender
|
||||
implementation admits a layout but can also work without it, then
|
||||
the appender should return <code>true</code>.
|
||||
|
||||
@since 0.8.4 */
|
||||
public
|
||||
boolean requiresLayout();
|
||||
}
|
||||
304
java/src/org/apache/log4j/AppenderSkeleton.java
Normal file
304
java/src/org/apache/log4j/AppenderSkeleton.java
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.Filter;
|
||||
import org.apache.log4j.spi.ErrorHandler;
|
||||
import org.apache.log4j.spi.OptionHandler;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
import org.apache.log4j.helpers.OnlyOnceErrorHandler;
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract superclass of the other appenders in the package.
|
||||
*
|
||||
* This class provides the code for common functionality, such as
|
||||
* support for threshold filtering and support for general filters.
|
||||
*
|
||||
* @since 0.8.1
|
||||
* @author Ceki Gülcü
|
||||
* */
|
||||
public abstract class AppenderSkeleton implements Appender, OptionHandler {
|
||||
|
||||
/** The layout variable does not need to be set if the appender
|
||||
implementation has its own layout. */
|
||||
protected Layout layout;
|
||||
|
||||
/** Appenders are named. */
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
There is no level threshold filtering by default. */
|
||||
protected Priority threshold;
|
||||
|
||||
/**
|
||||
It is assumed and enforced that errorHandler is never null.
|
||||
*/
|
||||
protected ErrorHandler errorHandler = new OnlyOnceErrorHandler();
|
||||
|
||||
/** The first filter in the filter chain. Set to <code>null</code>
|
||||
initially. */
|
||||
protected Filter headFilter;
|
||||
/** The last filter in the filter chain. */
|
||||
protected Filter tailFilter;
|
||||
|
||||
/**
|
||||
Is this appender closed?
|
||||
*/
|
||||
protected boolean closed = false;
|
||||
|
||||
/**
|
||||
* Create new instance.
|
||||
*/
|
||||
public AppenderSkeleton() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new instance.
|
||||
* Provided for compatibility with log4j 1.3.
|
||||
*
|
||||
* @param isActive true if appender is ready for use upon construction.
|
||||
* Not used in log4j 1.2.x.
|
||||
* @since 1.2.15
|
||||
*/
|
||||
protected AppenderSkeleton(final boolean isActive) {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Derived appenders should override this method if option structure
|
||||
requires it. */
|
||||
public
|
||||
void activateOptions() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Add a filter to end of the filter list.
|
||||
|
||||
@since 0.9.0
|
||||
*/
|
||||
public
|
||||
void addFilter(Filter newFilter) {
|
||||
if(headFilter == null) {
|
||||
headFilter = tailFilter = newFilter;
|
||||
} else {
|
||||
tailFilter.setNext(newFilter);
|
||||
tailFilter = newFilter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Subclasses of <code>AppenderSkeleton</code> should implement this
|
||||
method to perform actual logging. See also {@link #doAppend
|
||||
AppenderSkeleton.doAppend} method.
|
||||
|
||||
@since 0.9.0
|
||||
*/
|
||||
abstract
|
||||
protected
|
||||
void append(LoggingEvent event);
|
||||
|
||||
|
||||
/**
|
||||
Clear the filters chain.
|
||||
|
||||
@since 0.9.0 */
|
||||
public
|
||||
void clearFilters() {
|
||||
headFilter = tailFilter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
Finalize this appender by calling the derived class'
|
||||
<code>close</code> method.
|
||||
|
||||
@since 0.8.4 */
|
||||
public
|
||||
void finalize() {
|
||||
// An appender might be closed then garbage collected. There is no
|
||||
// point in closing twice.
|
||||
if(this.closed)
|
||||
return;
|
||||
|
||||
LogLog.debug("Finalizing appender named ["+name+"].");
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Return the currently set {@link ErrorHandler} for this
|
||||
Appender.
|
||||
|
||||
@since 0.9.0 */
|
||||
public
|
||||
ErrorHandler getErrorHandler() {
|
||||
return this.errorHandler;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns the head Filter.
|
||||
|
||||
@since 1.1
|
||||
*/
|
||||
public
|
||||
Filter getFilter() {
|
||||
return headFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
Return the first filter in the filter chain for this
|
||||
Appender. The return value may be <code>null</code> if no is
|
||||
filter is set.
|
||||
|
||||
*/
|
||||
public
|
||||
final
|
||||
Filter getFirstFilter() {
|
||||
return headFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the layout of this appender. The value may be null.
|
||||
*/
|
||||
public
|
||||
Layout getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns the name of this appender.
|
||||
@return name, may be null.
|
||||
*/
|
||||
public
|
||||
final
|
||||
String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns this appenders threshold level. See the {@link
|
||||
#setThreshold} method for the meaning of this option.
|
||||
|
||||
@since 1.1 */
|
||||
public
|
||||
Priority getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check whether the message level is below the appender's
|
||||
threshold. If there is no threshold set, then the return value is
|
||||
always <code>true</code>.
|
||||
|
||||
*/
|
||||
public
|
||||
boolean isAsSevereAsThreshold(Priority priority) {
|
||||
return ((threshold == null) || priority.isGreaterOrEqual(threshold));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method performs threshold checks and invokes filters before
|
||||
* delegating actual logging to the subclasses specific {@link
|
||||
* AppenderSkeleton#append} method.
|
||||
* */
|
||||
public
|
||||
synchronized
|
||||
void doAppend(LoggingEvent event) {
|
||||
if(closed) {
|
||||
LogLog.error("Attempted to append to closed appender named ["+name+"].");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!isAsSevereAsThreshold(event.getLevel())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Filter f = this.headFilter;
|
||||
|
||||
FILTER_LOOP:
|
||||
while(f != null) {
|
||||
switch(f.decide(event)) {
|
||||
case Filter.DENY: return;
|
||||
case Filter.ACCEPT: break FILTER_LOOP;
|
||||
case Filter.NEUTRAL: f = f.getNext();
|
||||
}
|
||||
}
|
||||
|
||||
this.append(event);
|
||||
}
|
||||
|
||||
/**
|
||||
Set the {@link ErrorHandler} for this Appender.
|
||||
@since 0.9.0
|
||||
*/
|
||||
public
|
||||
synchronized
|
||||
void setErrorHandler(ErrorHandler eh) {
|
||||
if(eh == null) {
|
||||
// We do not throw exception here since the cause is probably a
|
||||
// bad config file.
|
||||
LogLog.warn("You have tried to set a null error-handler.");
|
||||
} else {
|
||||
this.errorHandler = eh;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Set the layout for this appender. Note that some appenders have
|
||||
their own (fixed) layouts or do not use one. For example, the
|
||||
{@link org.apache.log4j.net.SocketAppender} ignores the layout set
|
||||
here.
|
||||
*/
|
||||
public
|
||||
void setLayout(Layout layout) {
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the name of this Appender.
|
||||
*/
|
||||
public
|
||||
void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the threshold level. All log events with lower level
|
||||
than the threshold level are ignored by the appender.
|
||||
|
||||
<p>In configuration files this option is specified by setting the
|
||||
value of the <b>Threshold</b> option to a level
|
||||
string, such as "DEBUG", "INFO" and so on.
|
||||
|
||||
@since 0.8.3 */
|
||||
public
|
||||
void setThreshold(Priority threshold) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
}
|
||||
596
java/src/org/apache/log4j/AsyncAppender.java
Normal file
596
java/src/org/apache/log4j/AsyncAppender.java
Normal file
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
// Contibutors: Aaron Greenhouse <aarong@cs.cmu.edu>
|
||||
// Thomas Tuft Muller <ttm@online.no>
|
||||
package org.apache.log4j;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.log4j.helpers.AppenderAttachableImpl;
|
||||
import org.apache.log4j.spi.AppenderAttachable;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
|
||||
/**
|
||||
* The AsyncAppender lets users log events asynchronously.
|
||||
* <p/>
|
||||
* <p/>
|
||||
* The AsyncAppender will collect the events sent to it and then dispatch them
|
||||
* to all the appenders that are attached to it. You can attach multiple
|
||||
* appenders to an AsyncAppender.
|
||||
* </p>
|
||||
* <p/>
|
||||
* <p/>
|
||||
* The AsyncAppender uses a separate thread to serve the events in its buffer.
|
||||
* </p>
|
||||
* <p/>
|
||||
* <b>Important note:</b> The <code>AsyncAppender</code> can only be script
|
||||
* configured using the {@link org.apache.log4j.xml.DOMConfigurator}.
|
||||
* </p>
|
||||
*
|
||||
* @author Ceki Gülcü
|
||||
* @author Curt Arnold
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public class AsyncAppender extends AppenderSkeleton
|
||||
implements AppenderAttachable {
|
||||
/**
|
||||
* The default buffer size is set to 128 events.
|
||||
*/
|
||||
public static final int DEFAULT_BUFFER_SIZE = 128;
|
||||
|
||||
/**
|
||||
* Event buffer, also used as monitor to protect itself and
|
||||
* discardMap from simulatenous modifications.
|
||||
*/
|
||||
private final List buffer = new ArrayList();
|
||||
|
||||
/**
|
||||
* Map of DiscardSummary objects keyed by logger name.
|
||||
*/
|
||||
private final Map discardMap = new HashMap();
|
||||
|
||||
/**
|
||||
* Buffer size.
|
||||
*/
|
||||
private int bufferSize = DEFAULT_BUFFER_SIZE;
|
||||
|
||||
/** Nested appenders. */
|
||||
AppenderAttachableImpl aai;
|
||||
|
||||
/**
|
||||
* Nested appenders.
|
||||
*/
|
||||
private final AppenderAttachableImpl appenders;
|
||||
|
||||
/**
|
||||
* Dispatcher.
|
||||
*/
|
||||
private final Thread dispatcher;
|
||||
|
||||
/**
|
||||
* Should location info be included in dispatched messages.
|
||||
*/
|
||||
private boolean locationInfo = false;
|
||||
|
||||
/**
|
||||
* Does appender block when buffer is full.
|
||||
*/
|
||||
private boolean blocking = true;
|
||||
|
||||
/**
|
||||
* Create new instance.
|
||||
*/
|
||||
public AsyncAppender() {
|
||||
appenders = new AppenderAttachableImpl();
|
||||
|
||||
//
|
||||
// only set for compatibility
|
||||
aai = appenders;
|
||||
|
||||
dispatcher =
|
||||
new Thread(new Dispatcher(this, buffer, discardMap, appenders));
|
||||
|
||||
// It is the user's responsibility to close appenders before
|
||||
// exiting.
|
||||
dispatcher.setDaemon(true);
|
||||
|
||||
// set the dispatcher priority to lowest possible value
|
||||
// dispatcher.setPriority(Thread.MIN_PRIORITY);
|
||||
dispatcher.setName("AsyncAppender-Dispatcher-" + dispatcher.getName());
|
||||
dispatcher.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add appender.
|
||||
*
|
||||
* @param newAppender appender to add, may not be null.
|
||||
*/
|
||||
public void addAppender(final Appender newAppender) {
|
||||
synchronized (appenders) {
|
||||
appenders.addAppender(newAppender);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void append(final LoggingEvent event) {
|
||||
//
|
||||
// if dispatcher thread has died then
|
||||
// append subsequent events synchronously
|
||||
// See bug 23021
|
||||
if ((dispatcher == null) || !dispatcher.isAlive() || (bufferSize <= 0)) {
|
||||
synchronized (appenders) {
|
||||
appenders.appendLoopOnAppenders(event);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the NDC and thread name for the calling thread as these
|
||||
// LoggingEvent fields were not set at event creation time.
|
||||
event.getNDC();
|
||||
event.getThreadName();
|
||||
// Get a copy of this thread's MDC.
|
||||
event.getMDCCopy();
|
||||
if (locationInfo) {
|
||||
event.getLocationInformation();
|
||||
}
|
||||
event.getRenderedMessage();
|
||||
event.getThrowableStrRep();
|
||||
|
||||
synchronized (buffer) {
|
||||
while (true) {
|
||||
int previousSize = buffer.size();
|
||||
|
||||
if (previousSize < bufferSize) {
|
||||
buffer.add(event);
|
||||
|
||||
//
|
||||
// if buffer had been empty
|
||||
// signal all threads waiting on buffer
|
||||
// to check their conditions.
|
||||
//
|
||||
if (previousSize == 0) {
|
||||
buffer.notifyAll();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Following code is only reachable if buffer is full
|
||||
//
|
||||
//
|
||||
// if blocking and thread is not already interrupted
|
||||
// and not the dispatcher then
|
||||
// wait for a buffer notification
|
||||
boolean discard = true;
|
||||
if (blocking
|
||||
&& !Thread.interrupted()
|
||||
&& Thread.currentThread() != dispatcher) {
|
||||
try {
|
||||
buffer.wait();
|
||||
discard = false;
|
||||
} catch (InterruptedException e) {
|
||||
//
|
||||
// reset interrupt status so
|
||||
// calling code can see interrupt on
|
||||
// their next wait or sleep.
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// if blocking is false or thread has been interrupted
|
||||
// add event to discard map.
|
||||
//
|
||||
if (discard) {
|
||||
String loggerName = event.getLoggerName();
|
||||
DiscardSummary summary = (DiscardSummary) discardMap.get(loggerName);
|
||||
|
||||
if (summary == null) {
|
||||
summary = new DiscardSummary(event);
|
||||
discardMap.put(loggerName, summary);
|
||||
} else {
|
||||
summary.add(event);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close this <code>AsyncAppender</code> by interrupting the dispatcher
|
||||
* thread which will process all pending events before exiting.
|
||||
*/
|
||||
public void close() {
|
||||
/**
|
||||
* Set closed flag and notify all threads to check their conditions.
|
||||
* Should result in dispatcher terminating.
|
||||
*/
|
||||
synchronized (buffer) {
|
||||
closed = true;
|
||||
buffer.notifyAll();
|
||||
}
|
||||
|
||||
try {
|
||||
dispatcher.join();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
org.apache.log4j.helpers.LogLog.error(
|
||||
"Got an InterruptedException while waiting for the "
|
||||
+ "dispatcher to finish.", e);
|
||||
}
|
||||
|
||||
//
|
||||
// close all attached appenders.
|
||||
//
|
||||
synchronized (appenders) {
|
||||
Enumeration iter = appenders.getAllAppenders();
|
||||
|
||||
if (iter != null) {
|
||||
while (iter.hasMoreElements()) {
|
||||
Object next = iter.nextElement();
|
||||
|
||||
if (next instanceof Appender) {
|
||||
((Appender) next).close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get iterator over attached appenders.
|
||||
* @return iterator or null if no attached appenders.
|
||||
*/
|
||||
public Enumeration getAllAppenders() {
|
||||
synchronized (appenders) {
|
||||
return appenders.getAllAppenders();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get appender by name.
|
||||
*
|
||||
* @param name name, may not be null.
|
||||
* @return matching appender or null.
|
||||
*/
|
||||
public Appender getAppender(final String name) {
|
||||
synchronized (appenders) {
|
||||
return appenders.getAppender(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the location of the logging request call
|
||||
* should be captured.
|
||||
*
|
||||
* @return the current value of the <b>LocationInfo</b> option.
|
||||
*/
|
||||
public boolean getLocationInfo() {
|
||||
return locationInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if specified appender is attached.
|
||||
* @param appender appender.
|
||||
* @return true if attached.
|
||||
*/
|
||||
public boolean isAttached(final Appender appender) {
|
||||
synchronized (appenders) {
|
||||
return appenders.isAttached(appender);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean requiresLayout() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and closes all attached appenders.
|
||||
*/
|
||||
public void removeAllAppenders() {
|
||||
synchronized (appenders) {
|
||||
appenders.removeAllAppenders();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an appender.
|
||||
* @param appender appender to remove.
|
||||
*/
|
||||
public void removeAppender(final Appender appender) {
|
||||
synchronized (appenders) {
|
||||
appenders.removeAppender(appender);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove appender by name.
|
||||
* @param name name.
|
||||
*/
|
||||
public void removeAppender(final String name) {
|
||||
synchronized (appenders) {
|
||||
appenders.removeAppender(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The <b>LocationInfo</b> option takes a boolean value. By default, it is
|
||||
* set to false which means there will be no effort to extract the location
|
||||
* information related to the event. As a result, the event that will be
|
||||
* ultimately logged will likely to contain the wrong location information
|
||||
* (if present in the log format).
|
||||
* <p/>
|
||||
* <p/>
|
||||
* Location information extraction is comparatively very slow and should be
|
||||
* avoided unless performance is not a concern.
|
||||
* </p>
|
||||
* @param flag true if location information should be extracted.
|
||||
*/
|
||||
public void setLocationInfo(final boolean flag) {
|
||||
locationInfo = flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of messages allowed in the event buffer
|
||||
* before the calling thread is blocked (if blocking is true)
|
||||
* or until messages are summarized and discarded. Changing
|
||||
* the size will not affect messages already in the buffer.
|
||||
*
|
||||
* @param size buffer size, must be positive.
|
||||
*/
|
||||
public void setBufferSize(final int size) {
|
||||
//
|
||||
// log4j 1.2 would throw exception if size was negative
|
||||
// and deadlock if size was zero.
|
||||
//
|
||||
if (size < 0) {
|
||||
throw new java.lang.NegativeArraySizeException("size");
|
||||
}
|
||||
|
||||
synchronized (buffer) {
|
||||
//
|
||||
// don't let size be zero.
|
||||
//
|
||||
bufferSize = (size < 1) ? 1 : size;
|
||||
buffer.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current buffer size.
|
||||
* @return the current value of the <b>BufferSize</b> option.
|
||||
*/
|
||||
public int getBufferSize() {
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether appender should wait if there is no
|
||||
* space available in the event buffer or immediately return.
|
||||
*
|
||||
* @since 1.2.14
|
||||
* @param value true if appender should wait until available space in buffer.
|
||||
*/
|
||||
public void setBlocking(final boolean value) {
|
||||
synchronized (buffer) {
|
||||
blocking = value;
|
||||
buffer.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether appender should block calling thread when buffer is full.
|
||||
* If false, messages will be counted by logger and a summary
|
||||
* message appended after the contents of the buffer have been appended.
|
||||
*
|
||||
* @since 1.2.14
|
||||
* @return true if calling thread will be blocked when buffer is full.
|
||||
*/
|
||||
public boolean getBlocking() {
|
||||
return blocking;
|
||||
}
|
||||
|
||||
/**
|
||||
* Summary of discarded logging events for a logger.
|
||||
*/
|
||||
private static final class DiscardSummary {
|
||||
/**
|
||||
* First event of the highest severity.
|
||||
*/
|
||||
private LoggingEvent maxEvent;
|
||||
|
||||
/**
|
||||
* Total count of messages discarded.
|
||||
*/
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* Create new instance.
|
||||
*
|
||||
* @param event event, may not be null.
|
||||
*/
|
||||
public DiscardSummary(final LoggingEvent event) {
|
||||
maxEvent = event;
|
||||
count = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add discarded event to summary.
|
||||
*
|
||||
* @param event event, may not be null.
|
||||
*/
|
||||
public void add(final LoggingEvent event) {
|
||||
if (event.getLevel().toInt() > maxEvent.getLevel().toInt()) {
|
||||
maxEvent = event;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create event with summary information.
|
||||
*
|
||||
* @return new event.
|
||||
*/
|
||||
public LoggingEvent createEvent() {
|
||||
String msg =
|
||||
MessageFormat.format(
|
||||
"Discarded {0} messages due to full event buffer including: {1}",
|
||||
new Object[] { new Integer(count), maxEvent.getMessage() });
|
||||
|
||||
return new LoggingEvent(
|
||||
"org.apache.log4j.AsyncAppender.DONT_REPORT_LOCATION",
|
||||
Logger.getLogger(maxEvent.getLoggerName()),
|
||||
maxEvent.getLevel(),
|
||||
msg,
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event dispatcher.
|
||||
*/
|
||||
private static class Dispatcher implements Runnable {
|
||||
/**
|
||||
* Parent AsyncAppender.
|
||||
*/
|
||||
private final AsyncAppender parent;
|
||||
|
||||
/**
|
||||
* Event buffer.
|
||||
*/
|
||||
private final List buffer;
|
||||
|
||||
/**
|
||||
* Map of DiscardSummary keyed by logger name.
|
||||
*/
|
||||
private final Map discardMap;
|
||||
|
||||
/**
|
||||
* Wrapped appenders.
|
||||
*/
|
||||
private final AppenderAttachableImpl appenders;
|
||||
|
||||
/**
|
||||
* Create new instance of dispatcher.
|
||||
*
|
||||
* @param parent parent AsyncAppender, may not be null.
|
||||
* @param buffer event buffer, may not be null.
|
||||
* @param discardMap discard map, may not be null.
|
||||
* @param appenders appenders, may not be null.
|
||||
*/
|
||||
public Dispatcher(
|
||||
final AsyncAppender parent, final List buffer, final Map discardMap,
|
||||
final AppenderAttachableImpl appenders) {
|
||||
|
||||
this.parent = parent;
|
||||
this.buffer = buffer;
|
||||
this.appenders = appenders;
|
||||
this.discardMap = discardMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void run() {
|
||||
boolean isActive = true;
|
||||
|
||||
//
|
||||
// if interrupted (unlikely), end thread
|
||||
//
|
||||
try {
|
||||
//
|
||||
// loop until the AsyncAppender is closed.
|
||||
//
|
||||
while (isActive) {
|
||||
LoggingEvent[] events = null;
|
||||
|
||||
//
|
||||
// extract pending events while synchronized
|
||||
// on buffer
|
||||
//
|
||||
synchronized (buffer) {
|
||||
int bufferSize = buffer.size();
|
||||
isActive = !parent.closed;
|
||||
|
||||
while ((bufferSize == 0) && isActive) {
|
||||
buffer.wait();
|
||||
bufferSize = buffer.size();
|
||||
isActive = !parent.closed;
|
||||
}
|
||||
|
||||
if (bufferSize > 0) {
|
||||
events = new LoggingEvent[bufferSize + discardMap.size()];
|
||||
buffer.toArray(events);
|
||||
|
||||
//
|
||||
// add events due to buffer overflow
|
||||
//
|
||||
int index = bufferSize;
|
||||
|
||||
for (
|
||||
Iterator iter = discardMap.values().iterator();
|
||||
iter.hasNext();) {
|
||||
events[index++] = ((DiscardSummary) iter.next()).createEvent();
|
||||
}
|
||||
|
||||
//
|
||||
// clear buffer and discard map
|
||||
//
|
||||
buffer.clear();
|
||||
discardMap.clear();
|
||||
|
||||
//
|
||||
// allow blocked appends to continue
|
||||
buffer.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// process events after lock on buffer is released.
|
||||
//
|
||||
if (events != null) {
|
||||
for (int i = 0; i < events.length; i++) {
|
||||
synchronized (appenders) {
|
||||
appenders.appendLoopOnAppenders(events[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
73
java/src/org/apache/log4j/BasicConfigurator.java
Normal file
73
java/src/org/apache/log4j/BasicConfigurator.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
// Contibutors: "Luke Blanshard" <Luke@quiq.com>
|
||||
// "Mark DONSZELMANN" <Mark.Donszelmann@cern.ch>
|
||||
// "Muly Oved" <mulyoved@hotmail.com>
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
|
||||
/**
|
||||
Use this class to quickly configure the package.
|
||||
|
||||
<p>For file based configuration see {@link
|
||||
PropertyConfigurator}. For XML based configuration see {@link
|
||||
org.apache.log4j.xml.DOMConfigurator DOMConfigurator}.
|
||||
|
||||
@since 0.8.1
|
||||
@author Ceki Gülcü */
|
||||
public class BasicConfigurator {
|
||||
|
||||
protected BasicConfigurator() {
|
||||
}
|
||||
|
||||
/**
|
||||
Add a {@link ConsoleAppender} that uses {@link PatternLayout}
|
||||
using the {@link PatternLayout#TTCC_CONVERSION_PATTERN} and
|
||||
prints to <code>System.out</code> to the root category. */
|
||||
static
|
||||
public
|
||||
void configure() {
|
||||
Logger root = Logger.getRootLogger();
|
||||
root.addAppender(new ConsoleAppender(
|
||||
new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN)));
|
||||
}
|
||||
|
||||
/**
|
||||
Add <code>appender</code> to the root category.
|
||||
@param appender The appender to add to the root category.
|
||||
*/
|
||||
static
|
||||
public
|
||||
void configure(Appender appender) {
|
||||
Logger root = Logger.getRootLogger();
|
||||
root.addAppender(appender);
|
||||
}
|
||||
|
||||
/**
|
||||
Reset the default hierarchy to its defaut. It is equivalent to
|
||||
calling
|
||||
<code>Category.getDefaultHierarchy().resetConfiguration()</code>.
|
||||
|
||||
See {@link Hierarchy#resetConfiguration()} for more details. */
|
||||
public
|
||||
static
|
||||
void resetConfiguration() {
|
||||
LogManager.resetConfiguration();
|
||||
}
|
||||
}
|
||||
1062
java/src/org/apache/log4j/Category.java
Normal file
1062
java/src/org/apache/log4j/Category.java
Normal file
File diff suppressed because it is too large
Load Diff
52
java/src/org/apache/log4j/CategoryKey.java
Normal file
52
java/src/org/apache/log4j/CategoryKey.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
/**
|
||||
CategoryKey is a wrapper for String that apparently accellerated
|
||||
hash table lookup in early JVM's.
|
||||
@author Ceki Gülcü
|
||||
*/
|
||||
class CategoryKey {
|
||||
|
||||
String name;
|
||||
int hashCache;
|
||||
|
||||
CategoryKey(String name) {
|
||||
this.name = name;
|
||||
hashCache = name.hashCode();
|
||||
}
|
||||
|
||||
final
|
||||
public
|
||||
int hashCode() {
|
||||
return hashCache;
|
||||
}
|
||||
|
||||
final
|
||||
public
|
||||
boolean equals(Object rArg) {
|
||||
if(this == rArg)
|
||||
return true;
|
||||
|
||||
if(rArg != null && CategoryKey.class == rArg.getClass())
|
||||
return name.equals(((CategoryKey)rArg ).name);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
220
java/src/org/apache/log4j/ConsoleAppender.java
Normal file
220
java/src/org/apache/log4j/ConsoleAppender.java
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
|
||||
/**
|
||||
* ConsoleAppender appends log events to <code>System.out</code> or
|
||||
* <code>System.err</code> using a layout specified by the user. The
|
||||
* default target is <code>System.out</code>.
|
||||
*
|
||||
* @author Ceki Gülcü
|
||||
* @author Curt Arnold
|
||||
* @since 1.1 */
|
||||
public class ConsoleAppender extends WriterAppender {
|
||||
|
||||
public static final String SYSTEM_OUT = "System.out";
|
||||
public static final String SYSTEM_ERR = "System.err";
|
||||
|
||||
protected String target = SYSTEM_OUT;
|
||||
|
||||
/**
|
||||
* Determines if the appender honors reassignments of System.out
|
||||
* or System.err made after configuration.
|
||||
*/
|
||||
private boolean follow = false;
|
||||
|
||||
/**
|
||||
* Constructs an unconfigured appender.
|
||||
*/
|
||||
public ConsoleAppender() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a configured appender.
|
||||
*
|
||||
* @param layout layout, may not be null.
|
||||
*/
|
||||
public ConsoleAppender(Layout layout) {
|
||||
this(layout, SYSTEM_OUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a configured appender.
|
||||
* @param layout layout, may not be null.
|
||||
* @param target target, either "System.err" or "System.out".
|
||||
*/
|
||||
public ConsoleAppender(Layout layout, String target) {
|
||||
setLayout(layout);
|
||||
setTarget(target);
|
||||
activateOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the <b>Target</b> option. Recognized values
|
||||
* are "System.out" and "System.err". Any other value will be
|
||||
* ignored.
|
||||
* */
|
||||
public
|
||||
void setTarget(String value) {
|
||||
String v = value.trim();
|
||||
|
||||
if (SYSTEM_OUT.equalsIgnoreCase(v)) {
|
||||
target = SYSTEM_OUT;
|
||||
} else if (SYSTEM_ERR.equalsIgnoreCase(v)) {
|
||||
target = SYSTEM_ERR;
|
||||
} else {
|
||||
targetWarn(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value of the <b>Target</b> property. The
|
||||
* default value of the option is "System.out".
|
||||
*
|
||||
* See also {@link #setTarget}.
|
||||
* */
|
||||
public
|
||||
String getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the appender honors reassignments of System.out
|
||||
* or System.err made after configuration.
|
||||
* @param newValue if true, appender will use value of System.out or
|
||||
* System.err in force at the time when logging events are appended.
|
||||
* @since 1.2.13
|
||||
*/
|
||||
public final void setFollow(final boolean newValue) {
|
||||
follow = newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the appender honors reassignments of System.out
|
||||
* or System.err made after configuration.
|
||||
* @return true if appender will use value of System.out or
|
||||
* System.err in force at the time when logging events are appended.
|
||||
* @since 1.2.13
|
||||
*/
|
||||
public final boolean getFollow() {
|
||||
return follow;
|
||||
}
|
||||
|
||||
void targetWarn(String val) {
|
||||
LogLog.warn("["+val+"] should be System.out or System.err.");
|
||||
LogLog.warn("Using previously set target, System.out by default.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the appender for use.
|
||||
*/
|
||||
public void activateOptions() {
|
||||
if (follow) {
|
||||
if (target.equals(SYSTEM_ERR)) {
|
||||
setWriter(createWriter(new SystemErrStream()));
|
||||
} else {
|
||||
setWriter(createWriter(new SystemOutStream()));
|
||||
}
|
||||
} else {
|
||||
if (target.equals(SYSTEM_ERR)) {
|
||||
setWriter(createWriter(System.err));
|
||||
} else {
|
||||
setWriter(createWriter(System.out));
|
||||
}
|
||||
}
|
||||
|
||||
super.activateOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected
|
||||
final
|
||||
void closeWriter() {
|
||||
if (follow) {
|
||||
super.closeWriter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of OutputStream that redirects to the
|
||||
* current System.err.
|
||||
*
|
||||
*/
|
||||
private static class SystemErrStream extends OutputStream {
|
||||
public SystemErrStream() {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
System.err.flush();
|
||||
}
|
||||
|
||||
public void write(final byte[] b) throws IOException {
|
||||
System.err.write(b);
|
||||
}
|
||||
|
||||
public void write(final byte[] b, final int off, final int len)
|
||||
throws IOException {
|
||||
System.err.write(b, off, len);
|
||||
}
|
||||
|
||||
public void write(final int b) throws IOException {
|
||||
System.err.write(b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of OutputStream that redirects to the
|
||||
* current System.out.
|
||||
*
|
||||
*/
|
||||
private static class SystemOutStream extends OutputStream {
|
||||
public SystemOutStream() {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
System.out.flush();
|
||||
}
|
||||
|
||||
public void write(final byte[] b) throws IOException {
|
||||
System.out.write(b);
|
||||
}
|
||||
|
||||
public void write(final byte[] b, final int off, final int len)
|
||||
throws IOException {
|
||||
System.out.write(b, off, len);
|
||||
}
|
||||
|
||||
public void write(final int b) throws IOException {
|
||||
System.out.write(b);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
454
java/src/org/apache/log4j/DailyRollingFileAppender.java
Normal file
454
java/src/org/apache/log4j/DailyRollingFileAppender.java
Normal file
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
DailyRollingFileAppender extends {@link FileAppender} so that the
|
||||
underlying file is rolled over at a user chosen frequency.
|
||||
|
||||
DailyRollingFileAppender has been observed to exhibit
|
||||
synchronization issues and data loss. The log4j extras
|
||||
companion includes alternatives which should be considered
|
||||
for new deployments and which are discussed in the documentation
|
||||
for org.apache.log4j.rolling.RollingFileAppender.
|
||||
|
||||
<p>The rolling schedule is specified by the <b>DatePattern</b>
|
||||
option. This pattern should follow the {@link SimpleDateFormat}
|
||||
conventions. In particular, you <em>must</em> escape literal text
|
||||
within a pair of single quotes. A formatted version of the date
|
||||
pattern is used as the suffix for the rolled file name.
|
||||
|
||||
<p>For example, if the <b>File</b> option is set to
|
||||
<code>/foo/bar.log</code> and the <b>DatePattern</b> set to
|
||||
<code>'.'yyyy-MM-dd</code>, on 2001-02-16 at midnight, the logging
|
||||
file <code>/foo/bar.log</code> will be copied to
|
||||
<code>/foo/bar.log.2001-02-16</code> and logging for 2001-02-17
|
||||
will continue in <code>/foo/bar.log</code> until it rolls over
|
||||
the next day.
|
||||
|
||||
<p>Is is possible to specify monthly, weekly, half-daily, daily,
|
||||
hourly, or minutely rollover schedules.
|
||||
|
||||
<p><table border="1" cellpadding="2">
|
||||
<tr>
|
||||
<th>DatePattern</th>
|
||||
<th>Rollover schedule</th>
|
||||
<th>Example</th>
|
||||
|
||||
<tr>
|
||||
<td><code>'.'yyyy-MM</code>
|
||||
<td>Rollover at the beginning of each month</td>
|
||||
|
||||
<td>At midnight of May 31st, 2002 <code>/foo/bar.log</code> will be
|
||||
copied to <code>/foo/bar.log.2002-05</code>. Logging for the month
|
||||
of June will be output to <code>/foo/bar.log</code> until it is
|
||||
also rolled over the next month.
|
||||
|
||||
<tr>
|
||||
<td><code>'.'yyyy-ww</code>
|
||||
|
||||
<td>Rollover at the first day of each week. The first day of the
|
||||
week depends on the locale.</td>
|
||||
|
||||
<td>Assuming the first day of the week is Sunday, on Saturday
|
||||
midnight, June 9th 2002, the file <i>/foo/bar.log</i> will be
|
||||
copied to <i>/foo/bar.log.2002-23</i>. Logging for the 24th week
|
||||
of 2002 will be output to <code>/foo/bar.log</code> until it is
|
||||
rolled over the next week.
|
||||
|
||||
<tr>
|
||||
<td><code>'.'yyyy-MM-dd</code>
|
||||
|
||||
<td>Rollover at midnight each day.</td>
|
||||
|
||||
<td>At midnight, on March 8th, 2002, <code>/foo/bar.log</code> will
|
||||
be copied to <code>/foo/bar.log.2002-03-08</code>. Logging for the
|
||||
9th day of March will be output to <code>/foo/bar.log</code> until
|
||||
it is rolled over the next day.
|
||||
|
||||
<tr>
|
||||
<td><code>'.'yyyy-MM-dd-a</code>
|
||||
|
||||
<td>Rollover at midnight and midday of each day.</td>
|
||||
|
||||
<td>At noon, on March 9th, 2002, <code>/foo/bar.log</code> will be
|
||||
copied to <code>/foo/bar.log.2002-03-09-AM</code>. Logging for the
|
||||
afternoon of the 9th will be output to <code>/foo/bar.log</code>
|
||||
until it is rolled over at midnight.
|
||||
|
||||
<tr>
|
||||
<td><code>'.'yyyy-MM-dd-HH</code>
|
||||
|
||||
<td>Rollover at the top of every hour.</td>
|
||||
|
||||
<td>At approximately 11:00.000 o'clock on March 9th, 2002,
|
||||
<code>/foo/bar.log</code> will be copied to
|
||||
<code>/foo/bar.log.2002-03-09-10</code>. Logging for the 11th hour
|
||||
of the 9th of March will be output to <code>/foo/bar.log</code>
|
||||
until it is rolled over at the beginning of the next hour.
|
||||
|
||||
|
||||
<tr>
|
||||
<td><code>'.'yyyy-MM-dd-HH-mm</code>
|
||||
|
||||
<td>Rollover at the beginning of every minute.</td>
|
||||
|
||||
<td>At approximately 11:23,000, on March 9th, 2001,
|
||||
<code>/foo/bar.log</code> will be copied to
|
||||
<code>/foo/bar.log.2001-03-09-10-22</code>. Logging for the minute
|
||||
of 11:23 (9th of March) will be output to
|
||||
<code>/foo/bar.log</code> until it is rolled over the next minute.
|
||||
|
||||
</table>
|
||||
|
||||
<p>Do not use the colon ":" character in anywhere in the
|
||||
<b>DatePattern</b> option. The text before the colon is interpeted
|
||||
as the protocol specificaion of a URL which is probably not what
|
||||
you want.
|
||||
|
||||
|
||||
@author Eirik Lygre
|
||||
@author Ceki Gülcü*/
|
||||
public class DailyRollingFileAppender extends FileAppender {
|
||||
|
||||
|
||||
// The code assumes that the following constants are in a increasing
|
||||
// sequence.
|
||||
static final int TOP_OF_TROUBLE=-1;
|
||||
static final int TOP_OF_MINUTE = 0;
|
||||
static final int TOP_OF_HOUR = 1;
|
||||
static final int HALF_DAY = 2;
|
||||
static final int TOP_OF_DAY = 3;
|
||||
static final int TOP_OF_WEEK = 4;
|
||||
static final int TOP_OF_MONTH = 5;
|
||||
|
||||
|
||||
/**
|
||||
The date pattern. By default, the pattern is set to
|
||||
"'.'yyyy-MM-dd" meaning daily rollover.
|
||||
*/
|
||||
private String datePattern = "'.'yyyy-MM-dd";
|
||||
|
||||
/**
|
||||
The log file will be renamed to the value of the
|
||||
scheduledFilename variable when the next interval is entered. For
|
||||
example, if the rollover period is one hour, the log file will be
|
||||
renamed to the value of "scheduledFilename" at the beginning of
|
||||
the next hour.
|
||||
|
||||
The precise time when a rollover occurs depends on logging
|
||||
activity.
|
||||
*/
|
||||
private String scheduledFilename;
|
||||
|
||||
/**
|
||||
The next time we estimate a rollover should occur. */
|
||||
private long nextCheck = System.currentTimeMillis () - 1;
|
||||
|
||||
Date now = new Date();
|
||||
|
||||
SimpleDateFormat sdf;
|
||||
|
||||
RollingCalendar rc = new RollingCalendar();
|
||||
|
||||
int checkPeriod = TOP_OF_TROUBLE;
|
||||
|
||||
// The gmtTimeZone is used only in computeCheckPeriod() method.
|
||||
static final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");
|
||||
|
||||
|
||||
/**
|
||||
The default constructor does nothing. */
|
||||
public DailyRollingFileAppender() {
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate a <code>DailyRollingFileAppender</code> and open the
|
||||
file designated by <code>filename</code>. The opened filename will
|
||||
become the ouput destination for this appender.
|
||||
|
||||
*/
|
||||
public DailyRollingFileAppender (Layout layout, String filename,
|
||||
String datePattern) throws IOException {
|
||||
super(layout, filename, true);
|
||||
this.datePattern = datePattern;
|
||||
activateOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
The <b>DatePattern</b> takes a string in the same format as
|
||||
expected by {@link SimpleDateFormat}. This options determines the
|
||||
rollover schedule.
|
||||
*/
|
||||
public void setDatePattern(String pattern) {
|
||||
datePattern = pattern;
|
||||
}
|
||||
|
||||
/** Returns the value of the <b>DatePattern</b> option. */
|
||||
public String getDatePattern() {
|
||||
return datePattern;
|
||||
}
|
||||
|
||||
public void activateOptions() {
|
||||
super.activateOptions();
|
||||
if(datePattern != null && fileName != null) {
|
||||
now.setTime(System.currentTimeMillis());
|
||||
sdf = new SimpleDateFormat(datePattern);
|
||||
int type = computeCheckPeriod();
|
||||
printPeriodicity(type);
|
||||
rc.setType(type);
|
||||
File file = new File(fileName);
|
||||
scheduledFilename = fileName+sdf.format(new Date(file.lastModified()));
|
||||
|
||||
} else {
|
||||
LogLog.error("Either File or DatePattern options are not set for appender ["
|
||||
+name+"].");
|
||||
}
|
||||
}
|
||||
|
||||
void printPeriodicity(int type) {
|
||||
switch(type) {
|
||||
case TOP_OF_MINUTE:
|
||||
LogLog.debug("Appender ["+name+"] to be rolled every minute.");
|
||||
break;
|
||||
case TOP_OF_HOUR:
|
||||
LogLog.debug("Appender ["+name
|
||||
+"] to be rolled on top of every hour.");
|
||||
break;
|
||||
case HALF_DAY:
|
||||
LogLog.debug("Appender ["+name
|
||||
+"] to be rolled at midday and midnight.");
|
||||
break;
|
||||
case TOP_OF_DAY:
|
||||
LogLog.debug("Appender ["+name
|
||||
+"] to be rolled at midnight.");
|
||||
break;
|
||||
case TOP_OF_WEEK:
|
||||
LogLog.debug("Appender ["+name
|
||||
+"] to be rolled at start of week.");
|
||||
break;
|
||||
case TOP_OF_MONTH:
|
||||
LogLog.debug("Appender ["+name
|
||||
+"] to be rolled at start of every month.");
|
||||
break;
|
||||
default:
|
||||
LogLog.warn("Unknown periodicity for appender ["+name+"].");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This method computes the roll over period by looping over the
|
||||
// periods, starting with the shortest, and stopping when the r0 is
|
||||
// different from from r1, where r0 is the epoch formatted according
|
||||
// the datePattern (supplied by the user) and r1 is the
|
||||
// epoch+nextMillis(i) formatted according to datePattern. All date
|
||||
// formatting is done in GMT and not local format because the test
|
||||
// logic is based on comparisons relative to 1970-01-01 00:00:00
|
||||
// GMT (the epoch).
|
||||
|
||||
int computeCheckPeriod() {
|
||||
RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.getDefault());
|
||||
// set sate to 1970-01-01 00:00:00 GMT
|
||||
Date epoch = new Date(0);
|
||||
if(datePattern != null) {
|
||||
for(int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
|
||||
simpleDateFormat.setTimeZone(gmtTimeZone); // do all date formatting in GMT
|
||||
String r0 = simpleDateFormat.format(epoch);
|
||||
rollingCalendar.setType(i);
|
||||
Date next = new Date(rollingCalendar.getNextCheckMillis(epoch));
|
||||
String r1 = simpleDateFormat.format(next);
|
||||
//System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1);
|
||||
if(r0 != null && r1 != null && !r0.equals(r1)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TOP_OF_TROUBLE; // Deliberately head for trouble...
|
||||
}
|
||||
|
||||
/**
|
||||
Rollover the current file to a new file.
|
||||
*/
|
||||
void rollOver() throws IOException {
|
||||
|
||||
/* Compute filename, but only if datePattern is specified */
|
||||
if (datePattern == null) {
|
||||
errorHandler.error("Missing DatePattern option in rollOver().");
|
||||
return;
|
||||
}
|
||||
|
||||
String datedFilename = fileName+sdf.format(now);
|
||||
// It is too early to roll over because we are still within the
|
||||
// bounds of the current interval. Rollover will occur once the
|
||||
// next interval is reached.
|
||||
if (scheduledFilename.equals(datedFilename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// close current file, and rename it to datedFilename
|
||||
this.closeFile();
|
||||
|
||||
File target = new File(scheduledFilename);
|
||||
if (target.exists()) {
|
||||
target.delete();
|
||||
}
|
||||
|
||||
File file = new File(fileName);
|
||||
boolean result = file.renameTo(target);
|
||||
if(result) {
|
||||
LogLog.debug(fileName +" -> "+ scheduledFilename);
|
||||
} else {
|
||||
LogLog.error("Failed to rename ["+fileName+"] to ["+scheduledFilename+"].");
|
||||
}
|
||||
|
||||
try {
|
||||
// This will also close the file. This is OK since multiple
|
||||
// close operations are safe.
|
||||
this.setFile(fileName, true, this.bufferedIO, this.bufferSize);
|
||||
}
|
||||
catch(IOException e) {
|
||||
errorHandler.error("setFile("+fileName+", true) call failed.");
|
||||
}
|
||||
scheduledFilename = datedFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method differentiates DailyRollingFileAppender from its
|
||||
* super class.
|
||||
*
|
||||
* <p>Before actually logging, this method will check whether it is
|
||||
* time to do a rollover. If it is, it will schedule the next
|
||||
* rollover time and then rollover.
|
||||
* */
|
||||
protected void subAppend(LoggingEvent event) {
|
||||
long n = System.currentTimeMillis();
|
||||
if (n >= nextCheck) {
|
||||
now.setTime(n);
|
||||
nextCheck = rc.getNextCheckMillis(now);
|
||||
try {
|
||||
rollOver();
|
||||
}
|
||||
catch(IOException ioe) {
|
||||
if (ioe instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
LogLog.error("rollOver() failed.", ioe);
|
||||
}
|
||||
}
|
||||
super.subAppend(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RollingCalendar is a helper class to DailyRollingFileAppender.
|
||||
* Given a periodicity type and the current time, it computes the
|
||||
* start of the next interval.
|
||||
* */
|
||||
class RollingCalendar extends GregorianCalendar {
|
||||
private static final long serialVersionUID = -3560331770601814177L;
|
||||
|
||||
int type = DailyRollingFileAppender.TOP_OF_TROUBLE;
|
||||
|
||||
RollingCalendar() {
|
||||
super();
|
||||
}
|
||||
|
||||
RollingCalendar(TimeZone tz, Locale locale) {
|
||||
super(tz, locale);
|
||||
}
|
||||
|
||||
void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public long getNextCheckMillis(Date now) {
|
||||
return getNextCheckDate(now).getTime();
|
||||
}
|
||||
|
||||
public Date getNextCheckDate(Date now) {
|
||||
this.setTime(now);
|
||||
|
||||
switch(type) {
|
||||
case DailyRollingFileAppender.TOP_OF_MINUTE:
|
||||
this.set(Calendar.SECOND, 0);
|
||||
this.set(Calendar.MILLISECOND, 0);
|
||||
this.add(Calendar.MINUTE, 1);
|
||||
break;
|
||||
case DailyRollingFileAppender.TOP_OF_HOUR:
|
||||
this.set(Calendar.MINUTE, 0);
|
||||
this.set(Calendar.SECOND, 0);
|
||||
this.set(Calendar.MILLISECOND, 0);
|
||||
this.add(Calendar.HOUR_OF_DAY, 1);
|
||||
break;
|
||||
case DailyRollingFileAppender.HALF_DAY:
|
||||
this.set(Calendar.MINUTE, 0);
|
||||
this.set(Calendar.SECOND, 0);
|
||||
this.set(Calendar.MILLISECOND, 0);
|
||||
int hour = get(Calendar.HOUR_OF_DAY);
|
||||
if(hour < 12) {
|
||||
this.set(Calendar.HOUR_OF_DAY, 12);
|
||||
} else {
|
||||
this.set(Calendar.HOUR_OF_DAY, 0);
|
||||
this.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
break;
|
||||
case DailyRollingFileAppender.TOP_OF_DAY:
|
||||
this.set(Calendar.HOUR_OF_DAY, 0);
|
||||
this.set(Calendar.MINUTE, 0);
|
||||
this.set(Calendar.SECOND, 0);
|
||||
this.set(Calendar.MILLISECOND, 0);
|
||||
this.add(Calendar.DATE, 1);
|
||||
break;
|
||||
case DailyRollingFileAppender.TOP_OF_WEEK:
|
||||
this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
|
||||
this.set(Calendar.HOUR_OF_DAY, 0);
|
||||
this.set(Calendar.MINUTE, 0);
|
||||
this.set(Calendar.SECOND, 0);
|
||||
this.set(Calendar.MILLISECOND, 0);
|
||||
this.add(Calendar.WEEK_OF_YEAR, 1);
|
||||
break;
|
||||
case DailyRollingFileAppender.TOP_OF_MONTH:
|
||||
this.set(Calendar.DATE, 1);
|
||||
this.set(Calendar.HOUR_OF_DAY, 0);
|
||||
this.set(Calendar.MINUTE, 0);
|
||||
this.set(Calendar.SECOND, 0);
|
||||
this.set(Calendar.MILLISECOND, 0);
|
||||
this.add(Calendar.MONTH, 1);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown periodicity type.");
|
||||
}
|
||||
return getTime();
|
||||
}
|
||||
}
|
||||
31
java/src/org/apache/log4j/DefaultCategoryFactory.java
Normal file
31
java/src/org/apache/log4j/DefaultCategoryFactory.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.LoggerFactory;
|
||||
|
||||
class DefaultCategoryFactory implements LoggerFactory {
|
||||
|
||||
DefaultCategoryFactory() {
|
||||
}
|
||||
|
||||
public
|
||||
Logger makeNewLoggerInstance(String name) {
|
||||
return new Logger(name);
|
||||
}
|
||||
}
|
||||
83
java/src/org/apache/log4j/DefaultThrowableRenderer.java
Normal file
83
java/src/org/apache/log4j/DefaultThrowableRenderer.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.ThrowableRenderer;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.LineNumberReader;
|
||||
import java.io.StringReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Default implementation of ThrowableRenderer using
|
||||
* Throwable.printStackTrace.
|
||||
*
|
||||
* @since 1.2.16
|
||||
*/
|
||||
public final class DefaultThrowableRenderer implements ThrowableRenderer {
|
||||
/**
|
||||
* Construct new instance.
|
||||
*/
|
||||
public DefaultThrowableRenderer() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public String[] doRender(final Throwable throwable) {
|
||||
return render(throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render throwable using Throwable.printStackTrace.
|
||||
* @param throwable throwable, may not be null.
|
||||
* @return string representation.
|
||||
*/
|
||||
public static String[] render(final Throwable throwable) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
try {
|
||||
throwable.printStackTrace(pw);
|
||||
} catch(RuntimeException ex) {
|
||||
}
|
||||
pw.flush();
|
||||
LineNumberReader reader = new LineNumberReader(
|
||||
new StringReader(sw.toString()));
|
||||
ArrayList lines = new ArrayList();
|
||||
try {
|
||||
String line = reader.readLine();
|
||||
while(line != null) {
|
||||
lines.add(line);
|
||||
line = reader.readLine();
|
||||
}
|
||||
} catch(IOException ex) {
|
||||
if (ex instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
lines.add(ex.toString());
|
||||
}
|
||||
String[] tempRep = new String[lines.size()];
|
||||
lines.toArray(tempRep);
|
||||
return tempRep;
|
||||
}
|
||||
}
|
||||
125
java/src/org/apache/log4j/Dispatcher.java
Normal file
125
java/src/org/apache/log4j/Dispatcher.java
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.helpers.AppenderAttachableImpl;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Obsolete AsyncAppender dispatcher provided for compatibility only.
|
||||
*
|
||||
* @deprecated Since 1.3.
|
||||
*/
|
||||
class Dispatcher extends Thread {
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
private org.apache.log4j.helpers.BoundedFIFO bf;
|
||||
private AppenderAttachableImpl aai;
|
||||
private boolean interrupted = false;
|
||||
AsyncAppender container;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param bf
|
||||
* @param container
|
||||
* @deprecated
|
||||
*/
|
||||
Dispatcher(org.apache.log4j.helpers.BoundedFIFO bf, AsyncAppender container) {
|
||||
this.bf = bf;
|
||||
this.container = container;
|
||||
this.aai = container.aai;
|
||||
|
||||
// It is the user's responsibility to close appenders before
|
||||
// exiting.
|
||||
this.setDaemon(true);
|
||||
|
||||
// set the dispatcher priority to lowest possible value
|
||||
this.setPriority(Thread.MIN_PRIORITY);
|
||||
this.setName("Dispatcher-" + getName());
|
||||
|
||||
// set the dispatcher priority to MIN_PRIORITY plus or minus 2
|
||||
// depending on the direction of MIN to MAX_PRIORITY.
|
||||
//+ (Thread.MAX_PRIORITY > Thread.MIN_PRIORITY ? 1 : -1)*2);
|
||||
}
|
||||
|
||||
void close() {
|
||||
synchronized (bf) {
|
||||
interrupted = true;
|
||||
|
||||
// We have a waiting dispacther if and only if bf.length is
|
||||
// zero. In that case, we need to give it a death kiss.
|
||||
if (bf.length() == 0) {
|
||||
bf.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The dispatching strategy is to wait until there are events in the buffer
|
||||
* to process. After having processed an event, we release the monitor
|
||||
* (variable bf) so that new events can be placed in the buffer, instead of
|
||||
* keeping the monitor and processing the remaining events in the buffer.
|
||||
*
|
||||
* <p>
|
||||
* Other approaches might yield better results.
|
||||
* </p>
|
||||
*/
|
||||
public void run() {
|
||||
//Category cat = Category.getInstance(Dispatcher.class.getName());
|
||||
LoggingEvent event;
|
||||
|
||||
while (true) {
|
||||
synchronized (bf) {
|
||||
if (bf.length() == 0) {
|
||||
// Exit loop if interrupted but only if the the buffer is empty.
|
||||
if (interrupted) {
|
||||
//cat.info("Exiting.");
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
//LogLog.debug("Waiting for new event to dispatch.");
|
||||
bf.wait();
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
event = bf.get();
|
||||
|
||||
if (bf.wasFull()) {
|
||||
//LogLog.debug("Notifying AsyncAppender about freed space.");
|
||||
bf.notify();
|
||||
}
|
||||
}
|
||||
|
||||
// synchronized
|
||||
synchronized (container.aai) {
|
||||
if ((aai != null) && (event != null)) {
|
||||
aai.appendLoopOnAppenders(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// while
|
||||
// close and remove all appenders
|
||||
aai.removeAllAppenders();
|
||||
}
|
||||
}
|
||||
559
java/src/org/apache/log4j/EnhancedPatternLayout.java
Normal file
559
java/src/org/apache/log4j/EnhancedPatternLayout.java
Normal file
@@ -0,0 +1,559 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.helpers.OptionConverter;
|
||||
import org.apache.log4j.helpers.PatternConverter;
|
||||
import org.apache.log4j.pattern.BridgePatternConverter;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
|
||||
// Contributors: Nelson Minar <nelson@monkey.org>
|
||||
// Anders Kristensen <akristensen@dynamicsoft.com>
|
||||
|
||||
/**
|
||||
* This class is an enhanced version of org.apache.log4j.PatternLayout
|
||||
* which was originally developed as part of the abandoned log4j 1.3
|
||||
* effort and has been available in the extras companion.
|
||||
* This pattern layout should be used in preference to
|
||||
* org.apache.log4j.PatternLayout except when compatibility
|
||||
* where PatternLayout has been extended either through subclassing
|
||||
* or alternative pattern parsers.
|
||||
*
|
||||
*
|
||||
* <p>A flexible layout configurable with pattern string. The goal of this class
|
||||
* is to {@link #format format} a {@link LoggingEvent} and return the results
|
||||
* in a {@link StringBuffer}. The format of the result depends on the
|
||||
* <em>conversion pattern</em>.
|
||||
* <p>
|
||||
*
|
||||
* <p>The conversion pattern is closely related to the conversion
|
||||
* pattern of the printf function in C. A conversion pattern is
|
||||
* composed of literal text and format control expressions called
|
||||
* <em>conversion specifiers</em>.
|
||||
*
|
||||
* <p><i>Note that you are free to insert any literal text within the
|
||||
* conversion pattern.</i>
|
||||
* </p>
|
||||
|
||||
<p>Each conversion specifier starts with a percent sign (%) and is
|
||||
followed by optional <em>format modifiers</em> and a <em>conversion
|
||||
character</em>. The conversion character specifies the type of
|
||||
data, e.g. category, priority, date, thread name. The format
|
||||
modifiers control such things as field width, padding, left and
|
||||
right justification. The following is a simple example.
|
||||
|
||||
<p>Let the conversion pattern be <b>"%-5p [%t]: %m%n"</b> and assume
|
||||
that the log4j environment was set to use a EnhancedPatternLayout. Then the
|
||||
statements
|
||||
<pre>
|
||||
Category root = Category.getRoot();
|
||||
root.debug("Message 1");
|
||||
root.warn("Message 2");
|
||||
</pre>
|
||||
would yield the output
|
||||
<pre>
|
||||
DEBUG [main]: Message 1
|
||||
WARN [main]: Message 2
|
||||
</pre>
|
||||
|
||||
<p>Note that there is no explicit separator between text and
|
||||
conversion specifiers. The pattern parser knows when it has reached
|
||||
the end of a conversion specifier when it reads a conversion
|
||||
character. In the example above the conversion specifier
|
||||
<b>%-5p</b> means the priority of the logging event should be left
|
||||
justified to a width of five characters.
|
||||
|
||||
The recognized conversion characters are
|
||||
|
||||
<p>
|
||||
<table border="1" CELLPADDING="8">
|
||||
<th>Conversion Character</th>
|
||||
<th>Effect</th>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>c</b></td>
|
||||
|
||||
<td>Used to output the category of the logging event. The
|
||||
category conversion specifier can be optionally followed by
|
||||
NameAbbreviator pattern.
|
||||
|
||||
<p>For example, for the category name "alpha.beta.gamma" the pattern
|
||||
<b>%c{2}</b> will output the last two elements ("beta.gamma"),
|
||||
<b>%c{-2}</b> will remove two elements leaving "gamma",
|
||||
<b>%c{1.}</b> will output "a.b.gamma".
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>C</b></td>
|
||||
|
||||
<td>Used to output the fully qualified class name of the caller
|
||||
issuing the logging request. This conversion specifier
|
||||
can be optionally followed by <em>precision specifier</em>, that
|
||||
is a decimal constant in brackets.
|
||||
|
||||
<td>Used to output the category of the logging event. The
|
||||
category conversion specifier can be optionally followed by
|
||||
NameAbbreviator pattern.
|
||||
|
||||
<p>For example, for the category name "alpha.beta.gamma" the pattern
|
||||
<b>%c{2}</b> will output the last two elements ("beta.gamma"),
|
||||
<b>%c{-2}</b> will remove two elements leaving "gamma",
|
||||
<b>%c{1.}</b> will output "a.b.gamma".
|
||||
|
||||
<p><b>WARNING</b> Generating the caller class information is
|
||||
slow. Thus, its use should be avoided unless execution speed is
|
||||
not an issue.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr> <td align=center><b>d</b></td> <td>Used to output the date of
|
||||
the logging event. The date conversion specifier may be
|
||||
followed by a set of braces containing a
|
||||
date and time pattern strings {@link java.text.SimpleDateFormat},
|
||||
<em>ABSOLUTE</em>, <em>DATE</em> or <em>ISO8601</em>
|
||||
and a set of braces containing a time zone id per
|
||||
{@link java.util.TimeZone#getTimeZone(String)}.
|
||||
For example, <b>%d{HH:mm:ss,SSS}</b>,
|
||||
<b>%d{dd MMM yyyy HH:mm:ss,SSS}</b>,
|
||||
<b>%d{DATE}</b> or <b>%d{HH:mm:ss}{GMT+0}</b>. If no date format specifier is given then
|
||||
ISO8601 format is assumed.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>F</b></td>
|
||||
|
||||
<td>Used to output the file name where the logging request was
|
||||
issued.
|
||||
|
||||
<p><b>WARNING</b> Generating caller location information is
|
||||
extremely slow and should be avoided unless execution speed
|
||||
is not an issue.
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>l</b></td>
|
||||
|
||||
<td>Used to output location information of the caller which generated
|
||||
the logging event.
|
||||
|
||||
<p>The location information depends on the JVM implementation but
|
||||
usually consists of the fully qualified name of the calling
|
||||
method followed by the callers source the file name and line
|
||||
number between parentheses.
|
||||
|
||||
<p>The location information can be very useful. However, its
|
||||
generation is <em>extremely</em> slow and should be avoided
|
||||
unless execution speed is not an issue.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>L</b></td>
|
||||
|
||||
<td>Used to output the line number from where the logging request
|
||||
was issued.
|
||||
|
||||
<p><b>WARNING</b> Generating caller location information is
|
||||
extremely slow and should be avoided unless execution speed
|
||||
is not an issue.
|
||||
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td align=center><b>m</b></td>
|
||||
<td>Used to output the application supplied message associated with
|
||||
the logging event.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>M</b></td>
|
||||
|
||||
<td>Used to output the method name where the logging request was
|
||||
issued.
|
||||
|
||||
<p><b>WARNING</b> Generating caller location information is
|
||||
extremely slow and should be avoided unless execution speed
|
||||
is not an issue.
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>n</b></td>
|
||||
|
||||
<td>Outputs the platform dependent line separator character or
|
||||
characters.
|
||||
|
||||
<p>This conversion character offers practically the same
|
||||
performance as using non-portable line separator strings such as
|
||||
"\n", or "\r\n". Thus, it is the preferred way of specifying a
|
||||
line separator.
|
||||
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>p</b></td>
|
||||
<td>Used to output the priority of the logging event.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td align=center><b>r</b></td>
|
||||
|
||||
<td>Used to output the number of milliseconds elapsed since the construction
|
||||
of the layout until the creation of the logging event.</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td align=center><b>t</b></td>
|
||||
|
||||
<td>Used to output the name of the thread that generated the
|
||||
logging event.</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td align=center><b>x</b></td>
|
||||
|
||||
<td>Used to output the NDC (nested diagnostic context) associated
|
||||
with the thread that generated the logging event.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td align=center><b>X</b></td>
|
||||
|
||||
<td>
|
||||
|
||||
<p>Used to output the MDC (mapped diagnostic context) associated
|
||||
with the thread that generated the logging event. The <b>X</b>
|
||||
conversion character can be followed by the key for the
|
||||
map placed between braces, as in <b>%X{clientNumber}</b> where
|
||||
<code>clientNumber</code> is the key. The value in the MDC
|
||||
corresponding to the key will be output. If no additional sub-option
|
||||
is specified, then the entire contents of the MDC key value pair set
|
||||
is output using a format {{key1,val1},{key2,val2}}</p>
|
||||
|
||||
<p>See {@link MDC} class for more details.
|
||||
</p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>properties</b></td>
|
||||
|
||||
<td>
|
||||
<p>Used to output the Properties associated
|
||||
with the logging event. The <b>properties</b>
|
||||
conversion word can be followed by the key for the
|
||||
map placed between braces, as in <b>%properties{application}</b> where
|
||||
<code>application</code> is the key. The value in the Properties bundle
|
||||
corresponding to the key will be output. If no additional sub-option
|
||||
is specified, then the entire contents of the Properties key value pair set
|
||||
is output using a format {{key1,val1},{key2,val2}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>throwable</b></td>
|
||||
|
||||
<td>
|
||||
<p>Used to output the Throwable trace that has been bound to the LoggingEvent, by
|
||||
default this will output the full trace as one would normally
|
||||
find by a call to Throwable.printStackTrace().
|
||||
<b>%throwable{short}</b> or <b>%throwable{1}</b> will output the first line of
|
||||
stack trace. <b>throwable{none}</b> or <b>throwable{0}</b> will suppress
|
||||
the stack trace. <b>%throwable{n}</b> will output n lines of stack trace
|
||||
if a positive integer or omit the last -n lines if a negative integer.
|
||||
If no %throwable pattern is specified, the appender will take
|
||||
responsibility to output the stack trace as it sees fit.</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td align=center><b>%</b></td>
|
||||
|
||||
<td>The sequence %% outputs a single percent sign.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<p>By default the relevant information is output as is. However,
|
||||
with the aid of format modifiers it is possible to change the
|
||||
minimum field width, the maximum field width and justification.
|
||||
|
||||
<p>The optional format modifier is placed between the percent sign
|
||||
and the conversion character.
|
||||
|
||||
<p>The first optional format modifier is the <em>left justification
|
||||
flag</em> which is just the minus (-) character. Then comes the
|
||||
optional <em>minimum field width</em> modifier. This is a decimal
|
||||
constant that represents the minimum number of characters to
|
||||
output. If the data item requires fewer characters, it is padded on
|
||||
either the left or the right until the minimum width is
|
||||
reached. The default is to pad on the left (right justify) but you
|
||||
can specify right padding with the left justification flag. The
|
||||
padding character is space. If the data item is larger than the
|
||||
minimum field width, the field is expanded to accommodate the
|
||||
data. The value is never truncated.
|
||||
|
||||
<p>This behavior can be changed using the <em>maximum field
|
||||
width</em> modifier which is designated by a period followed by a
|
||||
decimal constant. If the data item is longer than the maximum
|
||||
field, then the extra characters are removed from the
|
||||
<em>beginning</em> of the data item and not from the end. For
|
||||
example, it the maximum field width is eight and the data item is
|
||||
ten characters long, then the first two characters of the data item
|
||||
are dropped. This behavior deviates from the printf function in C
|
||||
where truncation is done from the end.
|
||||
|
||||
<p>Below are various format modifier examples for the category
|
||||
conversion specifier.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=1 CELLPADDING=8>
|
||||
<th>Format modifier
|
||||
<th>left justify
|
||||
<th>minimum width
|
||||
<th>maximum width
|
||||
<th>comment
|
||||
|
||||
<tr>
|
||||
<td align=center>%20c</td>
|
||||
<td align=center>false</td>
|
||||
<td align=center>20</td>
|
||||
<td align=center>none</td>
|
||||
|
||||
<td>Left pad with spaces if the category name is less than 20
|
||||
characters long.
|
||||
|
||||
<tr> <td align=center>%-20c</td> <td align=center>true</td> <td
|
||||
align=center>20</td> <td align=center>none</td> <td>Right pad with
|
||||
spaces if the category name is less than 20 characters long.
|
||||
|
||||
<tr>
|
||||
<td align=center>%.30c</td>
|
||||
<td align=center>NA</td>
|
||||
<td align=center>none</td>
|
||||
<td align=center>30</td>
|
||||
|
||||
<td>Truncate from the beginning if the category name is longer than 30
|
||||
characters.
|
||||
|
||||
<tr>
|
||||
<td align=center>%20.30c</td>
|
||||
<td align=center>false</td>
|
||||
<td align=center>20</td>
|
||||
<td align=center>30</td>
|
||||
|
||||
<td>Left pad with spaces if the category name is shorter than 20
|
||||
characters. However, if category name is longer than 30 characters,
|
||||
then truncate from the beginning.
|
||||
|
||||
<tr>
|
||||
<td align=center>%-20.30c</td>
|
||||
<td align=center>true</td>
|
||||
<td align=center>20</td>
|
||||
<td align=center>30</td>
|
||||
|
||||
<td>Right pad with spaces if the category name is shorter than 20
|
||||
characters. However, if category name is longer than 30 characters,
|
||||
then truncate from the beginning.
|
||||
|
||||
</table>
|
||||
|
||||
<p>Below are some examples of conversion patterns.
|
||||
|
||||
<dl>
|
||||
|
||||
<p><dt><b>%r [%t] %-5p %c %x - %m%n</b>
|
||||
<p><dd>This is essentially the TTCC layout.
|
||||
|
||||
<p><dt><b>%-6r [%15.15t] %-5p %30.30c %x - %m%n</b>
|
||||
|
||||
<p><dd>Similar to the TTCC layout except that the relative time is
|
||||
right padded if less than 6 digits, thread name is right padded if
|
||||
less than 15 characters and truncated if longer and the category
|
||||
name is left padded if shorter than 30 characters and truncated if
|
||||
longer.
|
||||
|
||||
</dl>
|
||||
|
||||
<p>The above text is largely inspired from Peter A. Darnell and
|
||||
Philip E. Margolis' highly recommended book "C -- a Software
|
||||
Engineering Approach", ISBN 0-387-97389-3.
|
||||
|
||||
@author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
|
||||
@author Ceki Gülcü
|
||||
|
||||
|
||||
@since 1.2.16 */
|
||||
public class EnhancedPatternLayout extends Layout {
|
||||
/** Default pattern string for log output. Currently set to the
|
||||
string <b>"%m%n"</b> which just prints the application supplied
|
||||
message. */
|
||||
public static final String DEFAULT_CONVERSION_PATTERN = "%m%n";
|
||||
|
||||
/** A conversion pattern equivalent to the TTCCCLayout.
|
||||
Current value is <b>%r [%t] %p %c %x - %m%n</b>. */
|
||||
public static final String TTCC_CONVERSION_PATTERN =
|
||||
"%r [%t] %p %c %x - %m%n";
|
||||
|
||||
/**
|
||||
* Initial size of internal buffer, no longer used.
|
||||
* @deprecated since 1.3
|
||||
*/
|
||||
protected final int BUF_SIZE = 256;
|
||||
|
||||
/**
|
||||
* Maximum capacity of internal buffer, no longer used.
|
||||
* @deprecated since 1.3
|
||||
*/
|
||||
protected final int MAX_CAPACITY = 1024;
|
||||
|
||||
/**
|
||||
* Customized pattern conversion rules are stored under this key in the
|
||||
* {@link org.apache.log4j.spi.LoggerRepository LoggerRepository} object store.
|
||||
*/
|
||||
public static final String PATTERN_RULE_REGISTRY = "PATTERN_RULE_REGISTRY";
|
||||
|
||||
|
||||
/**
|
||||
* Initial converter for pattern.
|
||||
*/
|
||||
private PatternConverter head;
|
||||
|
||||
/**
|
||||
* Conversion pattern.
|
||||
*/
|
||||
private String conversionPattern;
|
||||
|
||||
/**
|
||||
* True if any element in pattern formats information from exceptions.
|
||||
*/
|
||||
private boolean handlesExceptions;
|
||||
|
||||
/**
|
||||
Constructs a EnhancedPatternLayout using the DEFAULT_LAYOUT_PATTERN.
|
||||
|
||||
The default pattern just produces the application supplied message.
|
||||
*/
|
||||
public EnhancedPatternLayout() {
|
||||
this(DEFAULT_CONVERSION_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a EnhancedPatternLayout using the supplied conversion pattern.
|
||||
* @param pattern conversion pattern.
|
||||
*/
|
||||
public EnhancedPatternLayout(final String pattern) {
|
||||
this.conversionPattern = pattern;
|
||||
head = createPatternParser(
|
||||
(pattern == null) ? DEFAULT_CONVERSION_PATTERN : pattern).parse();
|
||||
if (head instanceof BridgePatternConverter) {
|
||||
handlesExceptions = !((BridgePatternConverter) head).ignoresThrowable();
|
||||
} else {
|
||||
handlesExceptions = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <b>ConversionPattern</b> option. This is the string which
|
||||
* controls formatting and consists of a mix of literal content and
|
||||
* conversion specifiers.
|
||||
*
|
||||
* @param conversionPattern conversion pattern.
|
||||
*/
|
||||
public void setConversionPattern(final String conversionPattern) {
|
||||
this.conversionPattern =
|
||||
OptionConverter.convertSpecialChars(conversionPattern);
|
||||
head = createPatternParser(this.conversionPattern).parse();
|
||||
if (head instanceof BridgePatternConverter) {
|
||||
handlesExceptions = !((BridgePatternConverter) head).ignoresThrowable();
|
||||
} else {
|
||||
handlesExceptions = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the <b>ConversionPattern</b> option.
|
||||
* @return conversion pattern.
|
||||
*/
|
||||
public String getConversionPattern() {
|
||||
return conversionPattern;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns PatternParser used to parse the conversion string. Subclasses
|
||||
may override this to return a subclass of PatternParser which recognize
|
||||
custom conversion characters.
|
||||
|
||||
@since 0.9.0
|
||||
*/
|
||||
protected org.apache.log4j.helpers.PatternParser createPatternParser(String pattern) {
|
||||
return new org.apache.log4j.pattern.BridgePatternParser(pattern);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Activates the conversion pattern. Do not forget to call this method after
|
||||
you change the parameters of the EnhancedPatternLayout instance.
|
||||
*/
|
||||
public void activateOptions() {
|
||||
// nothing to do.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Formats a logging event to a writer.
|
||||
* @param event logging event to be formatted.
|
||||
*/
|
||||
public String format(final LoggingEvent event) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for(PatternConverter c = head;
|
||||
c != null;
|
||||
c = c.next) {
|
||||
c.format(buf, event);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will return false if any of the conversion specifiers in the pattern
|
||||
* handles {@link Exception Exceptions}.
|
||||
* @return true if the pattern formats any information from exceptions.
|
||||
*/
|
||||
public boolean ignoresThrowable() {
|
||||
return !handlesExceptions;
|
||||
}
|
||||
}
|
||||
168
java/src/org/apache/log4j/EnhancedThrowableRenderer.java
Normal file
168
java/src/org/apache/log4j/EnhancedThrowableRenderer.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.ThrowableRenderer;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.security.CodeSource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Enhanced implementation of ThrowableRenderer. Uses Throwable.getStackTrace
|
||||
* if running on JDK 1.4 or later and delegates to DefaultThrowableRenderer.render
|
||||
* on earlier virtual machines.
|
||||
*
|
||||
* @since 1.2.16
|
||||
*/
|
||||
public final class EnhancedThrowableRenderer implements ThrowableRenderer {
|
||||
/**
|
||||
* Throwable.getStackTrace() method.
|
||||
*/
|
||||
private Method getStackTraceMethod;
|
||||
/**
|
||||
* StackTraceElement.getClassName() method.
|
||||
*/
|
||||
private Method getClassNameMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Construct new instance.
|
||||
*/
|
||||
public EnhancedThrowableRenderer() {
|
||||
try {
|
||||
Class[] noArgs = null;
|
||||
getStackTraceMethod = Throwable.class.getMethod("getStackTrace", noArgs);
|
||||
Class ste = Class.forName("java.lang.StackTraceElement");
|
||||
getClassNameMethod = ste.getMethod("getClassName", noArgs);
|
||||
} catch(Exception ex) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public String[] doRender(final Throwable throwable) {
|
||||
if (getStackTraceMethod != null) {
|
||||
try {
|
||||
Object[] noArgs = null;
|
||||
Object[] elements = (Object[]) getStackTraceMethod.invoke(throwable, noArgs);
|
||||
String[] lines = new String[elements.length + 1];
|
||||
lines[0] = throwable.toString();
|
||||
Map classMap = new HashMap();
|
||||
for(int i = 0; i < elements.length; i++) {
|
||||
lines[i+1] = formatElement(elements[i], classMap);
|
||||
}
|
||||
return lines;
|
||||
} catch(Exception ex) {
|
||||
}
|
||||
}
|
||||
return DefaultThrowableRenderer.render(throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format one element from stack trace.
|
||||
* @param element element, may not be null.
|
||||
* @param classMap map of class name to location.
|
||||
* @return string representation of element.
|
||||
*/
|
||||
private String formatElement(final Object element, final Map classMap) {
|
||||
StringBuffer buf = new StringBuffer("\tat ");
|
||||
buf.append(element);
|
||||
try {
|
||||
String className = getClassNameMethod.invoke(element, (Object[]) null).toString();
|
||||
Object classDetails = classMap.get(className);
|
||||
if (classDetails != null) {
|
||||
buf.append(classDetails);
|
||||
} else {
|
||||
Class cls = findClass(className);
|
||||
int detailStart = buf.length();
|
||||
buf.append('[');
|
||||
try {
|
||||
CodeSource source = cls.getProtectionDomain().getCodeSource();
|
||||
if (source != null) {
|
||||
URL locationURL = source.getLocation();
|
||||
if (locationURL != null) {
|
||||
//
|
||||
// if a file: URL
|
||||
//
|
||||
if ("file".equals(locationURL.getProtocol())) {
|
||||
String path = locationURL.getPath();
|
||||
if (path != null) {
|
||||
//
|
||||
// find the last file separator character
|
||||
//
|
||||
int lastSlash = path.lastIndexOf('/');
|
||||
int lastBack = path.lastIndexOf(File.separatorChar);
|
||||
if (lastBack > lastSlash) {
|
||||
lastSlash = lastBack;
|
||||
}
|
||||
//
|
||||
// if no separator or ends with separator (a directory)
|
||||
// then output the URL, otherwise just the file name.
|
||||
//
|
||||
if (lastSlash <= 0 || lastSlash == path.length() - 1) {
|
||||
buf.append(locationURL);
|
||||
} else {
|
||||
buf.append(path.substring(lastSlash + 1));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buf.append(locationURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(SecurityException ex) {
|
||||
}
|
||||
buf.append(':');
|
||||
Package pkg = cls.getPackage();
|
||||
if (pkg != null) {
|
||||
String implVersion = pkg.getImplementationVersion();
|
||||
if (implVersion != null) {
|
||||
buf.append(implVersion);
|
||||
}
|
||||
}
|
||||
buf.append(']');
|
||||
classMap.put(className, buf.substring(detailStart));
|
||||
}
|
||||
} catch(Exception ex) {
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find class given class name.
|
||||
* @param className class name, may not be null.
|
||||
* @return class, will not be null.
|
||||
* @throws ClassNotFoundException thrown if class can not be found.
|
||||
*/
|
||||
private Class findClass(final String className) throws ClassNotFoundException {
|
||||
try {
|
||||
return Thread.currentThread().getContextClassLoader().loadClass(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
try {
|
||||
return Class.forName(className);
|
||||
} catch (ClassNotFoundException e1) {
|
||||
return getClass().getClassLoader().loadClass(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
348
java/src/org/apache/log4j/FileAppender.java
Normal file
348
java/src/org/apache/log4j/FileAppender.java
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.Writer;
|
||||
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
import org.apache.log4j.helpers.QuietWriter;
|
||||
import org.apache.log4j.spi.ErrorCode;
|
||||
|
||||
// Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
|
||||
// Ben Sandee
|
||||
|
||||
/**
|
||||
* FileAppender appends log events to a file.
|
||||
*
|
||||
* <p>Support for <code>java.io.Writer</code> and console appending
|
||||
* has been deprecated and then removed. See the replacement
|
||||
* solutions: {@link WriterAppender} and {@link ConsoleAppender}.
|
||||
*
|
||||
* @author Ceki Gülcü
|
||||
* */
|
||||
public class FileAppender extends WriterAppender {
|
||||
|
||||
/** Controls file truncatation. The default value for this variable
|
||||
* is <code>true</code>, meaning that by default a
|
||||
* <code>FileAppender</code> will append to an existing file and not
|
||||
* truncate it.
|
||||
*
|
||||
* <p>This option is meaningful only if the FileAppender opens the
|
||||
* file.
|
||||
*/
|
||||
protected boolean fileAppend = true;
|
||||
|
||||
/**
|
||||
The name of the log file. */
|
||||
protected String fileName = null;
|
||||
|
||||
/**
|
||||
Do we do bufferedIO? */
|
||||
protected boolean bufferedIO = false;
|
||||
|
||||
/**
|
||||
* Determines the size of IO buffer be. Default is 8K.
|
||||
*/
|
||||
protected int bufferSize = 8*1024;
|
||||
|
||||
|
||||
/**
|
||||
The default constructor does not do anything.
|
||||
*/
|
||||
public
|
||||
FileAppender() {
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate a <code>FileAppender</code> and open the file
|
||||
designated by <code>filename</code>. The opened filename will
|
||||
become the output destination for this appender.
|
||||
|
||||
<p>If the <code>append</code> parameter is true, the file will be
|
||||
appended to. Otherwise, the file designated by
|
||||
<code>filename</code> will be truncated before being opened.
|
||||
|
||||
<p>If the <code>bufferedIO</code> parameter is <code>true</code>,
|
||||
then buffered IO will be used to write to the output file.
|
||||
|
||||
*/
|
||||
public
|
||||
FileAppender(Layout layout, String filename, boolean append, boolean bufferedIO,
|
||||
int bufferSize) throws IOException {
|
||||
this.layout = layout;
|
||||
this.setFile(filename, append, bufferedIO, bufferSize);
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate a FileAppender and open the file designated by
|
||||
<code>filename</code>. The opened filename will become the output
|
||||
destination for this appender.
|
||||
|
||||
<p>If the <code>append</code> parameter is true, the file will be
|
||||
appended to. Otherwise, the file designated by
|
||||
<code>filename</code> will be truncated before being opened.
|
||||
*/
|
||||
public
|
||||
FileAppender(Layout layout, String filename, boolean append)
|
||||
throws IOException {
|
||||
this.layout = layout;
|
||||
this.setFile(filename, append, false, bufferSize);
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate a FileAppender and open the file designated by
|
||||
<code>filename</code>. The opened filename will become the output
|
||||
destination for this appender.
|
||||
|
||||
<p>The file will be appended to. */
|
||||
public
|
||||
FileAppender(Layout layout, String filename) throws IOException {
|
||||
this(layout, filename, true);
|
||||
}
|
||||
|
||||
/**
|
||||
The <b>File</b> property takes a string value which should be the
|
||||
name of the file to append to.
|
||||
|
||||
<p><font color="#DD0044"><b>Note that the special values
|
||||
"System.out" or "System.err" are no longer honored.</b></font>
|
||||
|
||||
<p>Note: Actual opening of the file is made when {@link
|
||||
#activateOptions} is called, not when the options are set. */
|
||||
public void setFile(String file) {
|
||||
// Trim spaces from both ends. The users probably does not want
|
||||
// trailing spaces in file names.
|
||||
String val = file.trim();
|
||||
fileName = val;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the value of the <b>Append</b> option.
|
||||
*/
|
||||
public
|
||||
boolean getAppend() {
|
||||
return fileAppend;
|
||||
}
|
||||
|
||||
|
||||
/** Returns the value of the <b>File</b> option. */
|
||||
public
|
||||
String getFile() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
If the value of <b>File</b> is not <code>null</code>, then {@link
|
||||
#setFile} is called with the values of <b>File</b> and
|
||||
<b>Append</b> properties.
|
||||
|
||||
@since 0.8.1 */
|
||||
public
|
||||
void activateOptions() {
|
||||
if(fileName != null) {
|
||||
try {
|
||||
setFile(fileName, fileAppend, bufferedIO, bufferSize);
|
||||
}
|
||||
catch(java.io.IOException e) {
|
||||
errorHandler.error("setFile("+fileName+","+fileAppend+") call failed.",
|
||||
e, ErrorCode.FILE_OPEN_FAILURE);
|
||||
}
|
||||
} else {
|
||||
//LogLog.error("File option not set for appender ["+name+"].");
|
||||
LogLog.warn("File option not set for appender ["+name+"].");
|
||||
LogLog.warn("Are you using FileAppender instead of ConsoleAppender?");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Closes the previously opened file.
|
||||
*/
|
||||
protected
|
||||
void closeFile() {
|
||||
if(this.qw != null) {
|
||||
try {
|
||||
this.qw.close();
|
||||
}
|
||||
catch(java.io.IOException e) {
|
||||
if (e instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
// Exceptionally, it does not make sense to delegate to an
|
||||
// ErrorHandler. Since a closed appender is basically dead.
|
||||
LogLog.error("Could not close " + qw, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Get the value of the <b>BufferedIO</b> option.
|
||||
|
||||
<p>BufferedIO will significatnly increase performance on heavily
|
||||
loaded systems.
|
||||
|
||||
*/
|
||||
public
|
||||
boolean getBufferedIO() {
|
||||
return this.bufferedIO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the size of the IO buffer.
|
||||
*/
|
||||
public
|
||||
int getBufferSize() {
|
||||
return this.bufferSize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
The <b>Append</b> option takes a boolean value. It is set to
|
||||
<code>true</code> by default. If true, then <code>File</code>
|
||||
will be opened in append mode by {@link #setFile setFile} (see
|
||||
above). Otherwise, {@link #setFile setFile} will open
|
||||
<code>File</code> in truncate mode.
|
||||
|
||||
<p>Note: Actual opening of the file is made when {@link
|
||||
#activateOptions} is called, not when the options are set.
|
||||
*/
|
||||
public
|
||||
void setAppend(boolean flag) {
|
||||
fileAppend = flag;
|
||||
}
|
||||
|
||||
/**
|
||||
The <b>BufferedIO</b> option takes a boolean value. It is set to
|
||||
<code>false</code> by default. If true, then <code>File</code>
|
||||
will be opened and the resulting {@link java.io.Writer} wrapped
|
||||
around a {@link BufferedWriter}.
|
||||
|
||||
BufferedIO will significatnly increase performance on heavily
|
||||
loaded systems.
|
||||
|
||||
*/
|
||||
public
|
||||
void setBufferedIO(boolean bufferedIO) {
|
||||
this.bufferedIO = bufferedIO;
|
||||
if(bufferedIO) {
|
||||
immediateFlush = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the size of the IO buffer.
|
||||
*/
|
||||
public
|
||||
void setBufferSize(int bufferSize) {
|
||||
this.bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
<p>Sets and <i>opens</i> the file where the log output will
|
||||
go. The specified file must be writable.
|
||||
|
||||
<p>If there was already an opened file, then the previous file
|
||||
is closed first.
|
||||
|
||||
<p><b>Do not use this method directly. To configure a FileAppender
|
||||
or one of its subclasses, set its properties one by one and then
|
||||
call activateOptions.</b>
|
||||
|
||||
@param fileName The path to the log file.
|
||||
@param append If true will append to fileName. Otherwise will
|
||||
truncate fileName. */
|
||||
public
|
||||
synchronized
|
||||
void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
|
||||
throws IOException {
|
||||
LogLog.debug("setFile called: "+fileName+", "+append);
|
||||
|
||||
// It does not make sense to have immediate flush and bufferedIO.
|
||||
if(bufferedIO) {
|
||||
setImmediateFlush(false);
|
||||
}
|
||||
|
||||
reset();
|
||||
FileOutputStream ostream = null;
|
||||
try {
|
||||
//
|
||||
// attempt to create file
|
||||
//
|
||||
ostream = new FileOutputStream(fileName, append);
|
||||
} catch(FileNotFoundException ex) {
|
||||
//
|
||||
// if parent directory does not exist then
|
||||
// attempt to create it and try to create file
|
||||
// see bug 9150
|
||||
//
|
||||
String parentName = new File(fileName).getParent();
|
||||
if (parentName != null) {
|
||||
File parentDir = new File(parentName);
|
||||
if(!parentDir.exists() && parentDir.mkdirs()) {
|
||||
ostream = new FileOutputStream(fileName, append);
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
Writer fw = createWriter(ostream);
|
||||
if(bufferedIO) {
|
||||
fw = new BufferedWriter(fw, bufferSize);
|
||||
}
|
||||
this.setQWForFiles(fw);
|
||||
this.fileName = fileName;
|
||||
this.fileAppend = append;
|
||||
this.bufferedIO = bufferedIO;
|
||||
this.bufferSize = bufferSize;
|
||||
writeHeader();
|
||||
LogLog.debug("setFile ended");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Sets the quiet writer being used.
|
||||
|
||||
This method is overriden by {@link RollingFileAppender}.
|
||||
*/
|
||||
protected
|
||||
void setQWForFiles(Writer writer) {
|
||||
this.qw = new QuietWriter(writer, errorHandler);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Close any previously opened file and call the parent's
|
||||
<code>reset</code>. */
|
||||
protected
|
||||
void reset() {
|
||||
closeFile();
|
||||
this.fileName = null;
|
||||
super.reset();
|
||||
}
|
||||
}
|
||||
|
||||
267
java/src/org/apache/log4j/HTMLLayout.java
Normal file
267
java/src/org/apache/log4j/HTMLLayout.java
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
import org.apache.log4j.spi.LocationInfo;
|
||||
import org.apache.log4j.helpers.Transform;
|
||||
|
||||
/**
|
||||
* This layout outputs events in a HTML table.
|
||||
*
|
||||
* Appenders using this layout should have their encoding
|
||||
* set to UTF-8 or UTF-16, otherwise events containing
|
||||
* non ASCII characters could result in corrupted
|
||||
* log files.
|
||||
*
|
||||
* @author Ceki Gülcü
|
||||
*/
|
||||
public class HTMLLayout extends Layout {
|
||||
|
||||
protected final int BUF_SIZE = 256;
|
||||
protected final int MAX_CAPACITY = 1024;
|
||||
|
||||
static String TRACE_PREFIX = "<br> ";
|
||||
|
||||
// output buffer appended to when format() is invoked
|
||||
private StringBuffer sbuf = new StringBuffer(BUF_SIZE);
|
||||
|
||||
/**
|
||||
A string constant used in naming the option for setting the the
|
||||
location information flag. Current value of this string
|
||||
constant is <b>LocationInfo</b>.
|
||||
|
||||
<p>Note that all option keys are case sensitive.
|
||||
|
||||
@deprecated Options are now handled using the JavaBeans paradigm.
|
||||
This constant is not longer needed and will be removed in the
|
||||
<em>near</em> term.
|
||||
|
||||
*/
|
||||
public static final String LOCATION_INFO_OPTION = "LocationInfo";
|
||||
|
||||
/**
|
||||
A string constant used in naming the option for setting the the
|
||||
HTML document title. Current value of this string
|
||||
constant is <b>Title</b>.
|
||||
*/
|
||||
public static final String TITLE_OPTION = "Title";
|
||||
|
||||
// Print no location info by default
|
||||
boolean locationInfo = false;
|
||||
|
||||
String title = "Log4J Log Messages";
|
||||
|
||||
/**
|
||||
The <b>LocationInfo</b> option takes a boolean value. By
|
||||
default, it is set to false which means there will be no location
|
||||
information output by this layout. If the the option is set to
|
||||
true, then the file name and line number of the statement
|
||||
at the origin of the log statement will be output.
|
||||
|
||||
<p>If you are embedding this layout within an {@link
|
||||
org.apache.log4j.net.SMTPAppender} then make sure to set the
|
||||
<b>LocationInfo</b> option of that appender as well.
|
||||
*/
|
||||
public
|
||||
void setLocationInfo(boolean flag) {
|
||||
locationInfo = flag;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the current value of the <b>LocationInfo</b> option.
|
||||
*/
|
||||
public
|
||||
boolean getLocationInfo() {
|
||||
return locationInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
The <b>Title</b> option takes a String value. This option sets the
|
||||
document title of the generated HTML document.
|
||||
|
||||
<p>Defaults to 'Log4J Log Messages'.
|
||||
*/
|
||||
public
|
||||
void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the current value of the <b>Title</b> option.
|
||||
*/
|
||||
public
|
||||
String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the content type output by this layout, i.e "text/html".
|
||||
*/
|
||||
public
|
||||
String getContentType() {
|
||||
return "text/html";
|
||||
}
|
||||
|
||||
/**
|
||||
No options to activate.
|
||||
*/
|
||||
public
|
||||
void activateOptions() {
|
||||
}
|
||||
|
||||
public
|
||||
String format(LoggingEvent event) {
|
||||
|
||||
if(sbuf.capacity() > MAX_CAPACITY) {
|
||||
sbuf = new StringBuffer(BUF_SIZE);
|
||||
} else {
|
||||
sbuf.setLength(0);
|
||||
}
|
||||
|
||||
sbuf.append(Layout.LINE_SEP + "<tr>" + Layout.LINE_SEP);
|
||||
|
||||
sbuf.append("<td>");
|
||||
sbuf.append(event.timeStamp - LoggingEvent.getStartTime());
|
||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
||||
|
||||
String escapedThread = Transform.escapeTags(event.getThreadName());
|
||||
sbuf.append("<td title=\"" + escapedThread + " thread\">");
|
||||
sbuf.append(escapedThread);
|
||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
||||
|
||||
sbuf.append("<td title=\"Level\">");
|
||||
if (event.getLevel().equals(Level.DEBUG)) {
|
||||
sbuf.append("<font color=\"#339933\">");
|
||||
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
|
||||
sbuf.append("</font>");
|
||||
}
|
||||
else if(event.getLevel().isGreaterOrEqual(Level.WARN)) {
|
||||
sbuf.append("<font color=\"#993300\"><strong>");
|
||||
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
|
||||
sbuf.append("</strong></font>");
|
||||
} else {
|
||||
sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
|
||||
}
|
||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
||||
|
||||
String escapedLogger = Transform.escapeTags(event.getLoggerName());
|
||||
sbuf.append("<td title=\"" + escapedLogger + " category\">");
|
||||
sbuf.append(escapedLogger);
|
||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
||||
|
||||
if(locationInfo) {
|
||||
LocationInfo locInfo = event.getLocationInformation();
|
||||
sbuf.append("<td>");
|
||||
sbuf.append(Transform.escapeTags(locInfo.getFileName()));
|
||||
sbuf.append(':');
|
||||
sbuf.append(locInfo.getLineNumber());
|
||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
||||
}
|
||||
|
||||
sbuf.append("<td title=\"Message\">");
|
||||
sbuf.append(Transform.escapeTags(event.getRenderedMessage()));
|
||||
sbuf.append("</td>" + Layout.LINE_SEP);
|
||||
sbuf.append("</tr>" + Layout.LINE_SEP);
|
||||
|
||||
if (event.getNDC() != null) {
|
||||
sbuf.append("<tr><td bgcolor=\"#EEEEEE\" style=\"font-size : xx-small;\" colspan=\"6\" title=\"Nested Diagnostic Context\">");
|
||||
sbuf.append("NDC: " + Transform.escapeTags(event.getNDC()));
|
||||
sbuf.append("</td></tr>" + Layout.LINE_SEP);
|
||||
}
|
||||
|
||||
String[] s = event.getThrowableStrRep();
|
||||
if(s != null) {
|
||||
sbuf.append("<tr><td bgcolor=\"#993300\" style=\"color:White; font-size : xx-small;\" colspan=\"6\">");
|
||||
appendThrowableAsHTML(s, sbuf);
|
||||
sbuf.append("</td></tr>" + Layout.LINE_SEP);
|
||||
}
|
||||
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
void appendThrowableAsHTML(String[] s, StringBuffer sbuf) {
|
||||
if(s != null) {
|
||||
int len = s.length;
|
||||
if(len == 0)
|
||||
return;
|
||||
sbuf.append(Transform.escapeTags(s[0]));
|
||||
sbuf.append(Layout.LINE_SEP);
|
||||
for(int i = 1; i < len; i++) {
|
||||
sbuf.append(TRACE_PREFIX);
|
||||
sbuf.append(Transform.escapeTags(s[i]));
|
||||
sbuf.append(Layout.LINE_SEP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns appropriate HTML headers.
|
||||
*/
|
||||
public
|
||||
String getHeader() {
|
||||
StringBuffer sbuf = new StringBuffer();
|
||||
sbuf.append("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">" + Layout.LINE_SEP);
|
||||
sbuf.append("<html>" + Layout.LINE_SEP);
|
||||
sbuf.append("<head>" + Layout.LINE_SEP);
|
||||
sbuf.append("<title>" + title + "</title>" + Layout.LINE_SEP);
|
||||
sbuf.append("<style type=\"text/css\">" + Layout.LINE_SEP);
|
||||
sbuf.append("<!--" + Layout.LINE_SEP);
|
||||
sbuf.append("body, table {font-family: arial,sans-serif; font-size: x-small;}" + Layout.LINE_SEP);
|
||||
sbuf.append("th {background: #336699; color: #FFFFFF; text-align: left;}" + Layout.LINE_SEP);
|
||||
sbuf.append("-->" + Layout.LINE_SEP);
|
||||
sbuf.append("</style>" + Layout.LINE_SEP);
|
||||
sbuf.append("</head>" + Layout.LINE_SEP);
|
||||
sbuf.append("<body bgcolor=\"#FFFFFF\" topmargin=\"6\" leftmargin=\"6\">" + Layout.LINE_SEP);
|
||||
sbuf.append("<hr size=\"1\" noshade>" + Layout.LINE_SEP);
|
||||
sbuf.append("Log session start time " + new java.util.Date() + "<br>" + Layout.LINE_SEP);
|
||||
sbuf.append("<br>" + Layout.LINE_SEP);
|
||||
sbuf.append("<table cellspacing=\"0\" cellpadding=\"4\" border=\"1\" bordercolor=\"#224466\" width=\"100%\">" + Layout.LINE_SEP);
|
||||
sbuf.append("<tr>" + Layout.LINE_SEP);
|
||||
sbuf.append("<th>Time</th>" + Layout.LINE_SEP);
|
||||
sbuf.append("<th>Thread</th>" + Layout.LINE_SEP);
|
||||
sbuf.append("<th>Level</th>" + Layout.LINE_SEP);
|
||||
sbuf.append("<th>Category</th>" + Layout.LINE_SEP);
|
||||
if(locationInfo) {
|
||||
sbuf.append("<th>File:Line</th>" + Layout.LINE_SEP);
|
||||
}
|
||||
sbuf.append("<th>Message</th>" + Layout.LINE_SEP);
|
||||
sbuf.append("</tr>" + Layout.LINE_SEP);
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the appropriate HTML footers.
|
||||
*/
|
||||
public
|
||||
String getFooter() {
|
||||
StringBuffer sbuf = new StringBuffer();
|
||||
sbuf.append("</table>" + Layout.LINE_SEP);
|
||||
sbuf.append("<br>" + Layout.LINE_SEP);
|
||||
sbuf.append("</body></html>");
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
The HTML layout handles the throwable contained in logging
|
||||
events. Hence, this method return <code>false</code>. */
|
||||
public
|
||||
boolean ignoresThrowable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
577
java/src/org/apache/log4j/Hierarchy.java
Normal file
577
java/src/org/apache/log4j/Hierarchy.java
Normal file
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
// WARNING This class MUST not have references to the Category or
|
||||
// WARNING RootCategory classes in its static initiliazation neither
|
||||
// WARNING directly nor indirectly.
|
||||
|
||||
// Contributors:
|
||||
// Luke Blanshard <luke@quiq.com>
|
||||
// Mario Schomburg - IBM Global Services/Germany
|
||||
// Anders Kristensen
|
||||
// Igor Poteryaev
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.apache.log4j.spi.LoggerFactory;
|
||||
import org.apache.log4j.spi.HierarchyEventListener;
|
||||
import org.apache.log4j.spi.LoggerRepository;
|
||||
import org.apache.log4j.spi.RendererSupport;
|
||||
import org.apache.log4j.or.RendererMap;
|
||||
import org.apache.log4j.or.ObjectRenderer;
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
import org.apache.log4j.spi.ThrowableRendererSupport;
|
||||
import org.apache.log4j.spi.ThrowableRenderer;
|
||||
|
||||
/**
|
||||
This class is specialized in retrieving loggers by name and also
|
||||
maintaining the logger hierarchy.
|
||||
|
||||
<p><em>The casual user does not have to deal with this class
|
||||
directly.</em>
|
||||
|
||||
<p>The structure of the logger hierarchy is maintained by the
|
||||
{@link #getLogger} method. The hierarchy is such that children link
|
||||
to their parent but parents do not have any pointers to their
|
||||
children. Moreover, loggers can be instantiated in any order, in
|
||||
particular descendant before ancestor.
|
||||
|
||||
<p>In case a descendant is created before a particular ancestor,
|
||||
then it creates a provision node for the ancestor and adds itself
|
||||
to the provision node. Other descendants of the same ancestor add
|
||||
themselves to the previously created provision node.
|
||||
|
||||
@author Ceki Gülcü
|
||||
|
||||
*/
|
||||
public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRendererSupport {
|
||||
|
||||
private LoggerFactory defaultFactory;
|
||||
private Vector listeners;
|
||||
|
||||
Hashtable ht;
|
||||
Logger root;
|
||||
RendererMap rendererMap;
|
||||
|
||||
int thresholdInt;
|
||||
Level threshold;
|
||||
|
||||
boolean emittedNoAppenderWarning = false;
|
||||
boolean emittedNoResourceBundleWarning = false;
|
||||
|
||||
private ThrowableRenderer throwableRenderer = null;
|
||||
|
||||
/**
|
||||
Create a new logger hierarchy.
|
||||
|
||||
@param root The root of the new hierarchy.
|
||||
|
||||
*/
|
||||
public
|
||||
Hierarchy(Logger root) {
|
||||
ht = new Hashtable();
|
||||
listeners = new Vector(1);
|
||||
this.root = root;
|
||||
// Enable all level levels by default.
|
||||
setThreshold(Level.ALL);
|
||||
this.root.setHierarchy(this);
|
||||
rendererMap = new RendererMap();
|
||||
defaultFactory = new DefaultCategoryFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
Add an object renderer for a specific class.
|
||||
*/
|
||||
public
|
||||
void addRenderer(Class classToRender, ObjectRenderer or) {
|
||||
rendererMap.put(classToRender, or);
|
||||
}
|
||||
|
||||
public
|
||||
void addHierarchyEventListener(HierarchyEventListener listener) {
|
||||
if(listeners.contains(listener)) {
|
||||
LogLog.warn("Ignoring attempt to add an existent listener.");
|
||||
} else {
|
||||
listeners.addElement(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
This call will clear all logger definitions from the internal
|
||||
hashtable. Invoking this method will irrevocably mess up the
|
||||
logger hierarchy.
|
||||
|
||||
<p>You should <em>really</em> know what you are doing before
|
||||
invoking this method.
|
||||
|
||||
@since 0.9.0 */
|
||||
public
|
||||
void clear() {
|
||||
//System.out.println("\n\nAbout to clear internal hash table.");
|
||||
ht.clear();
|
||||
}
|
||||
|
||||
public
|
||||
void emitNoAppenderWarning(Category cat) {
|
||||
// No appenders in hierarchy, warn user only once.
|
||||
if(!this.emittedNoAppenderWarning) {
|
||||
LogLog.warn("No appenders could be found for logger (" +
|
||||
cat.getName() + ").");
|
||||
LogLog.warn("Please initialize the log4j system properly.");
|
||||
LogLog.warn("See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.");
|
||||
this.emittedNoAppenderWarning = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Check if the named logger exists in the hierarchy. If so return
|
||||
its reference, otherwise returns <code>null</code>.
|
||||
|
||||
@param name The name of the logger to search for.
|
||||
|
||||
*/
|
||||
public
|
||||
Logger exists(String name) {
|
||||
Object o = ht.get(new CategoryKey(name));
|
||||
if(o instanceof Logger) {
|
||||
return (Logger) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The string form of {@link #setThreshold(Level)}.
|
||||
*/
|
||||
public
|
||||
void setThreshold(String levelStr) {
|
||||
Level l = (Level) Level.toLevel(levelStr, null);
|
||||
if(l != null) {
|
||||
setThreshold(l);
|
||||
} else {
|
||||
LogLog.warn("Could not convert ["+levelStr+"] to Level.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Enable logging for logging requests with level <code>l</code> or
|
||||
higher. By default all levels are enabled.
|
||||
|
||||
@param l The minimum level for which logging requests are sent to
|
||||
their appenders. */
|
||||
public
|
||||
void setThreshold(Level l) {
|
||||
if(l != null) {
|
||||
thresholdInt = l.level;
|
||||
threshold = l;
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
void fireAddAppenderEvent(Category logger, Appender appender) {
|
||||
if(listeners != null) {
|
||||
int size = listeners.size();
|
||||
HierarchyEventListener listener;
|
||||
for(int i = 0; i < size; i++) {
|
||||
listener = (HierarchyEventListener) listeners.elementAt(i);
|
||||
listener.addAppenderEvent(logger, appender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fireRemoveAppenderEvent(Category logger, Appender appender) {
|
||||
if(listeners != null) {
|
||||
int size = listeners.size();
|
||||
HierarchyEventListener listener;
|
||||
for(int i = 0; i < size; i++) {
|
||||
listener = (HierarchyEventListener) listeners.elementAt(i);
|
||||
listener.removeAppenderEvent(logger, appender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a {@link Level} representation of the <code>enable</code>
|
||||
state.
|
||||
|
||||
@since 1.2 */
|
||||
public
|
||||
Level getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an integer representation of the this repository's
|
||||
threshold.
|
||||
|
||||
@since 1.2 */
|
||||
//public
|
||||
//int getThresholdInt() {
|
||||
// return thresholdInt;
|
||||
//}
|
||||
|
||||
|
||||
/**
|
||||
Return a new logger instance named as the first parameter using
|
||||
the default factory.
|
||||
|
||||
<p>If a logger of that name already exists, then it will be
|
||||
returned. Otherwise, a new logger will be instantiated and
|
||||
then linked with its existing ancestors as well as children.
|
||||
|
||||
@param name The name of the logger to retrieve.
|
||||
|
||||
*/
|
||||
public
|
||||
Logger getLogger(String name) {
|
||||
return getLogger(name, defaultFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
Return a new logger instance named as the first parameter using
|
||||
<code>factory</code>.
|
||||
|
||||
<p>If a logger of that name already exists, then it will be
|
||||
returned. Otherwise, a new logger will be instantiated by the
|
||||
<code>factory</code> parameter and linked with its existing
|
||||
ancestors as well as children.
|
||||
|
||||
@param name The name of the logger to retrieve.
|
||||
@param factory The factory that will make the new logger instance.
|
||||
|
||||
*/
|
||||
public
|
||||
Logger getLogger(String name, LoggerFactory factory) {
|
||||
//System.out.println("getInstance("+name+") called.");
|
||||
CategoryKey key = new CategoryKey(name);
|
||||
// Synchronize to prevent write conflicts. Read conflicts (in
|
||||
// getChainedLevel method) are possible only if variable
|
||||
// assignments are non-atomic.
|
||||
Logger logger;
|
||||
|
||||
synchronized(ht) {
|
||||
Object o = ht.get(key);
|
||||
if(o == null) {
|
||||
logger = factory.makeNewLoggerInstance(name);
|
||||
logger.setHierarchy(this);
|
||||
ht.put(key, logger);
|
||||
updateParents(logger);
|
||||
return logger;
|
||||
} else if(o instanceof Logger) {
|
||||
return (Logger) o;
|
||||
} else if (o instanceof ProvisionNode) {
|
||||
//System.out.println("("+name+") ht.get(this) returned ProvisionNode");
|
||||
logger = factory.makeNewLoggerInstance(name);
|
||||
logger.setHierarchy(this);
|
||||
ht.put(key, logger);
|
||||
updateChildren((ProvisionNode) o, logger);
|
||||
updateParents(logger);
|
||||
return logger;
|
||||
}
|
||||
else {
|
||||
// It should be impossible to arrive here
|
||||
return null; // but let's keep the compiler happy.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all the currently defined categories in this hierarchy as
|
||||
an {@link java.util.Enumeration Enumeration}.
|
||||
|
||||
<p>The root logger is <em>not</em> included in the returned
|
||||
{@link Enumeration}. */
|
||||
public
|
||||
Enumeration getCurrentLoggers() {
|
||||
// The accumlation in v is necessary because not all elements in
|
||||
// ht are Logger objects as there might be some ProvisionNodes
|
||||
// as well.
|
||||
Vector v = new Vector(ht.size());
|
||||
|
||||
Enumeration elems = ht.elements();
|
||||
while(elems.hasMoreElements()) {
|
||||
Object o = elems.nextElement();
|
||||
if(o instanceof Logger) {
|
||||
v.addElement(o);
|
||||
}
|
||||
}
|
||||
return v.elements();
|
||||
}
|
||||
|
||||
/**
|
||||
@deprecated Please use {@link #getCurrentLoggers} instead.
|
||||
*/
|
||||
public
|
||||
Enumeration getCurrentCategories() {
|
||||
return getCurrentLoggers();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the renderer map for this hierarchy.
|
||||
*/
|
||||
public
|
||||
RendererMap getRendererMap() {
|
||||
return rendererMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the root of this hierarchy.
|
||||
|
||||
@since 0.9.0
|
||||
*/
|
||||
public
|
||||
Logger getRootLogger() {
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
This method will return <code>true</code> if this repository is
|
||||
disabled for <code>level</code> object passed as parameter and
|
||||
<code>false</code> otherwise. See also the {@link
|
||||
#setThreshold(Level) threshold} emthod. */
|
||||
public
|
||||
boolean isDisabled(int level) {
|
||||
return thresholdInt > level;
|
||||
}
|
||||
|
||||
/**
|
||||
@deprecated Deprecated with no replacement.
|
||||
*/
|
||||
public
|
||||
void overrideAsNeeded(String override) {
|
||||
LogLog.warn("The Hiearchy.overrideAsNeeded method has been deprecated.");
|
||||
}
|
||||
|
||||
/**
|
||||
Reset all values contained in this hierarchy instance to their
|
||||
default. This removes all appenders from all categories, sets
|
||||
the level of all non-root categories to <code>null</code>,
|
||||
sets their additivity flag to <code>true</code> and sets the level
|
||||
of the root logger to {@link Level#DEBUG DEBUG}. Moreover,
|
||||
message disabling is set its default "off" value.
|
||||
|
||||
<p>Existing categories are not removed. They are just reset.
|
||||
|
||||
<p>This method should be used sparingly and with care as it will
|
||||
block all logging until it is completed.</p>
|
||||
|
||||
@since 0.8.5 */
|
||||
public
|
||||
void resetConfiguration() {
|
||||
|
||||
getRootLogger().setLevel((Level) Level.DEBUG);
|
||||
root.setResourceBundle(null);
|
||||
setThreshold(Level.ALL);
|
||||
|
||||
// the synchronization is needed to prevent JDK 1.2.x hashtable
|
||||
// surprises
|
||||
synchronized(ht) {
|
||||
shutdown(); // nested locks are OK
|
||||
|
||||
Enumeration cats = getCurrentLoggers();
|
||||
while(cats.hasMoreElements()) {
|
||||
Logger c = (Logger) cats.nextElement();
|
||||
c.setLevel(null);
|
||||
c.setAdditivity(true);
|
||||
c.setResourceBundle(null);
|
||||
}
|
||||
}
|
||||
rendererMap.clear();
|
||||
throwableRenderer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
Does nothing.
|
||||
|
||||
@deprecated Deprecated with no replacement.
|
||||
*/
|
||||
public
|
||||
void setDisableOverride(String override) {
|
||||
LogLog.warn("The Hiearchy.setDisableOverride method has been deprecated.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Used by subclasses to add a renderer to the hierarchy passed as parameter.
|
||||
*/
|
||||
public
|
||||
void setRenderer(Class renderedClass, ObjectRenderer renderer) {
|
||||
rendererMap.put(renderedClass, renderer);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void setThrowableRenderer(final ThrowableRenderer renderer) {
|
||||
throwableRenderer = renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public ThrowableRenderer getThrowableRenderer() {
|
||||
return throwableRenderer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Shutting down a hierarchy will <em>safely</em> close and remove
|
||||
all appenders in all categories including the root logger.
|
||||
|
||||
<p>Some appenders such as {@link org.apache.log4j.net.SocketAppender}
|
||||
and {@link AsyncAppender} need to be closed before the
|
||||
application exists. Otherwise, pending logging events might be
|
||||
lost.
|
||||
|
||||
<p>The <code>shutdown</code> method is careful to close nested
|
||||
appenders before closing regular appenders. This is allows
|
||||
configurations where a regular appender is attached to a logger
|
||||
and again to a nested appender.
|
||||
|
||||
|
||||
@since 1.0 */
|
||||
public
|
||||
void shutdown() {
|
||||
Logger root = getRootLogger();
|
||||
|
||||
// begin by closing nested appenders
|
||||
root.closeNestedAppenders();
|
||||
|
||||
synchronized(ht) {
|
||||
Enumeration cats = this.getCurrentLoggers();
|
||||
while(cats.hasMoreElements()) {
|
||||
Logger c = (Logger) cats.nextElement();
|
||||
c.closeNestedAppenders();
|
||||
}
|
||||
|
||||
// then, remove all appenders
|
||||
root.removeAllAppenders();
|
||||
cats = this.getCurrentLoggers();
|
||||
while(cats.hasMoreElements()) {
|
||||
Logger c = (Logger) cats.nextElement();
|
||||
c.removeAllAppenders();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This method loops through all the *potential* parents of
|
||||
'cat'. There 3 possible cases:
|
||||
|
||||
1) No entry for the potential parent of 'cat' exists
|
||||
|
||||
We create a ProvisionNode for this potential parent and insert
|
||||
'cat' in that provision node.
|
||||
|
||||
2) There entry is of type Logger for the potential parent.
|
||||
|
||||
The entry is 'cat's nearest existing parent. We update cat's
|
||||
parent field with this entry. We also break from the loop
|
||||
because updating our parent's parent is our parent's
|
||||
responsibility.
|
||||
|
||||
3) There entry is of type ProvisionNode for this potential parent.
|
||||
|
||||
We add 'cat' to the list of children for this potential parent.
|
||||
*/
|
||||
final
|
||||
private
|
||||
void updateParents(Logger cat) {
|
||||
String name = cat.name;
|
||||
int length = name.length();
|
||||
boolean parentFound = false;
|
||||
|
||||
//System.out.println("UpdateParents called for " + name);
|
||||
|
||||
// if name = "w.x.y.z", loop thourgh "w.x.y", "w.x" and "w", but not "w.x.y.z"
|
||||
for(int i = name.lastIndexOf('.', length-1); i >= 0;
|
||||
i = name.lastIndexOf('.', i-1)) {
|
||||
String substr = name.substring(0, i);
|
||||
|
||||
//System.out.println("Updating parent : " + substr);
|
||||
CategoryKey key = new CategoryKey(substr); // simple constructor
|
||||
Object o = ht.get(key);
|
||||
// Create a provision node for a future parent.
|
||||
if(o == null) {
|
||||
//System.out.println("No parent "+substr+" found. Creating ProvisionNode.");
|
||||
ProvisionNode pn = new ProvisionNode(cat);
|
||||
ht.put(key, pn);
|
||||
} else if(o instanceof Category) {
|
||||
parentFound = true;
|
||||
cat.parent = (Category) o;
|
||||
//System.out.println("Linking " + cat.name + " -> " + ((Category) o).name);
|
||||
break; // no need to update the ancestors of the closest ancestor
|
||||
} else if(o instanceof ProvisionNode) {
|
||||
((ProvisionNode) o).addElement(cat);
|
||||
} else {
|
||||
Exception e = new IllegalStateException("unexpected object type " +
|
||||
o.getClass() + " in ht.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// If we could not find any existing parents, then link with root.
|
||||
if(!parentFound)
|
||||
cat.parent = root;
|
||||
}
|
||||
|
||||
/**
|
||||
We update the links for all the children that placed themselves
|
||||
in the provision node 'pn'. The second argument 'cat' is a
|
||||
reference for the newly created Logger, parent of all the
|
||||
children in 'pn'
|
||||
|
||||
We loop on all the children 'c' in 'pn':
|
||||
|
||||
If the child 'c' has been already linked to a child of
|
||||
'cat' then there is no need to update 'c'.
|
||||
|
||||
Otherwise, we set cat's parent field to c's parent and set
|
||||
c's parent field to cat.
|
||||
|
||||
*/
|
||||
final
|
||||
private
|
||||
void updateChildren(ProvisionNode pn, Logger logger) {
|
||||
//System.out.println("updateChildren called for " + logger.name);
|
||||
final int last = pn.size();
|
||||
|
||||
for(int i = 0; i < last; i++) {
|
||||
Logger l = (Logger) pn.elementAt(i);
|
||||
//System.out.println("Updating child " +p.name);
|
||||
|
||||
// Unless this child already points to a correct (lower) parent,
|
||||
// make cat.parent point to l.parent and l.parent to cat.
|
||||
if(!l.parent.name.startsWith(logger.name)) {
|
||||
logger.parent = l.parent;
|
||||
l.parent = logger;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
89
java/src/org/apache/log4j/Layout.java
Normal file
89
java/src/org/apache/log4j/Layout.java
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.OptionHandler;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
Extend this abstract class to create your own log layout format.
|
||||
|
||||
@author Ceki Gülcü
|
||||
|
||||
*/
|
||||
|
||||
public abstract class Layout implements OptionHandler {
|
||||
|
||||
// Note that the line.separator property can be looked up even by
|
||||
// applets.
|
||||
public final static String LINE_SEP = System.getProperty("line.separator");
|
||||
public final static int LINE_SEP_LEN = LINE_SEP.length();
|
||||
|
||||
|
||||
/**
|
||||
Implement this method to create your own layout format.
|
||||
*/
|
||||
abstract
|
||||
public
|
||||
String format(LoggingEvent event);
|
||||
|
||||
/**
|
||||
Returns the content type output by this layout. The base class
|
||||
returns "text/plain".
|
||||
*/
|
||||
public
|
||||
String getContentType() {
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the header for the layout format. The base class returns
|
||||
<code>null</code>. */
|
||||
public
|
||||
String getHeader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the footer for the layout format. The base class returns
|
||||
<code>null</code>. */
|
||||
public
|
||||
String getFooter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
If the layout handles the throwable object contained within
|
||||
{@link LoggingEvent}, then the layout should return
|
||||
<code>false</code>. Otherwise, if the layout ignores throwable
|
||||
object, then the layout should return <code>true</code>.
|
||||
If ignoresThrowable is true, the appender is responsible for
|
||||
rendering the throwable.
|
||||
|
||||
<p>The {@link SimpleLayout}, {@link TTCCLayout}, {@link
|
||||
PatternLayout} all return <code>true</code>. The {@link
|
||||
org.apache.log4j.xml.XMLLayout} returns <code>false</code>.
|
||||
|
||||
@since 0.8.4 */
|
||||
abstract
|
||||
public
|
||||
boolean ignoresThrowable();
|
||||
|
||||
}
|
||||
224
java/src/org/apache/log4j/Level.java
Normal file
224
java/src/org/apache/log4j/Level.java
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
// Contributors: Kitching Simon <Simon.Kitching@orange.ch>
|
||||
// Nicholas Wolff
|
||||
|
||||
package org.apache.log4j;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
Defines the minimum set of levels recognized by the system, that is
|
||||
<code>OFF</code>, <code>FATAL</code>, <code>ERROR</code>,
|
||||
<code>WARN</code>, <code>INFO</code, <code>DEBUG</code> and
|
||||
<code>ALL</code>.
|
||||
|
||||
<p>The <code>Level</code> class may be subclassed to define a larger
|
||||
level set.
|
||||
|
||||
@author Ceki Gülcü
|
||||
|
||||
*/
|
||||
public class Level extends Priority implements Serializable {
|
||||
|
||||
/**
|
||||
* TRACE level integer value.
|
||||
* @since 1.2.12
|
||||
*/
|
||||
public static final int TRACE_INT = 5000;
|
||||
|
||||
/**
|
||||
The <code>OFF</code> has the highest possible rank and is
|
||||
intended to turn off logging. */
|
||||
final static public Level OFF = new Level(OFF_INT, "OFF", 0);
|
||||
|
||||
/**
|
||||
The <code>FATAL</code> level designates very severe error
|
||||
events that will presumably lead the application to abort.
|
||||
*/
|
||||
final static public Level FATAL = new Level(FATAL_INT, "FATAL", 0);
|
||||
|
||||
/**
|
||||
The <code>ERROR</code> level designates error events that
|
||||
might still allow the application to continue running. */
|
||||
final static public Level ERROR = new Level(ERROR_INT, "ERROR", 3);
|
||||
|
||||
/**
|
||||
The <code>WARN</code> level designates potentially harmful situations.
|
||||
*/
|
||||
final static public Level WARN = new Level(WARN_INT, "WARN", 4);
|
||||
|
||||
/**
|
||||
The <code>INFO</code> level designates informational messages
|
||||
that highlight the progress of the application at coarse-grained
|
||||
level. */
|
||||
final static public Level INFO = new Level(INFO_INT, "INFO", 6);
|
||||
|
||||
/**
|
||||
The <code>DEBUG</code> Level designates fine-grained
|
||||
informational events that are most useful to debug an
|
||||
application. */
|
||||
final static public Level DEBUG = new Level(DEBUG_INT, "DEBUG", 7);
|
||||
|
||||
/**
|
||||
* The <code>TRACE</code> Level designates finer-grained
|
||||
* informational events than the <code>DEBUG</code level.
|
||||
* @since 1.2.12
|
||||
*/
|
||||
public static final Level TRACE = new Level(TRACE_INT, "TRACE", 7);
|
||||
|
||||
|
||||
/**
|
||||
The <code>ALL</code> has the lowest possible rank and is intended to
|
||||
turn on all logging. */
|
||||
final static public Level ALL = new Level(ALL_INT, "ALL", 7);
|
||||
|
||||
/**
|
||||
* Serialization version id.
|
||||
*/
|
||||
static final long serialVersionUID = 3491141966387921974L;
|
||||
|
||||
/**
|
||||
Instantiate a Level object.
|
||||
*/
|
||||
protected
|
||||
Level(int level, String levelStr, int syslogEquivalent) {
|
||||
super(level, levelStr, syslogEquivalent);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convert the string passed as argument to a level. If the
|
||||
conversion fails, then this method returns {@link #DEBUG}.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Level toLevel(String sArg) {
|
||||
return (Level) toLevel(sArg, Level.DEBUG);
|
||||
}
|
||||
|
||||
/**
|
||||
Convert an integer passed as argument to a level. If the
|
||||
conversion fails, then this method returns {@link #DEBUG}.
|
||||
|
||||
*/
|
||||
public
|
||||
static
|
||||
Level toLevel(int val) {
|
||||
return (Level) toLevel(val, Level.DEBUG);
|
||||
}
|
||||
|
||||
/**
|
||||
Convert an integer passed as argument to a level. If the
|
||||
conversion fails, then this method returns the specified default.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Level toLevel(int val, Level defaultLevel) {
|
||||
switch(val) {
|
||||
case ALL_INT: return ALL;
|
||||
case DEBUG_INT: return Level.DEBUG;
|
||||
case INFO_INT: return Level.INFO;
|
||||
case WARN_INT: return Level.WARN;
|
||||
case ERROR_INT: return Level.ERROR;
|
||||
case FATAL_INT: return Level.FATAL;
|
||||
case OFF_INT: return OFF;
|
||||
case TRACE_INT: return Level.TRACE;
|
||||
default: return defaultLevel;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Convert the string passed as argument to a level. If the
|
||||
conversion fails, then this method returns the value of
|
||||
<code>defaultLevel</code>.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Level toLevel(String sArg, Level defaultLevel) {
|
||||
if(sArg == null)
|
||||
return defaultLevel;
|
||||
|
||||
String s = sArg.toUpperCase();
|
||||
|
||||
if(s.equals("ALL")) return Level.ALL;
|
||||
if(s.equals("DEBUG")) return Level.DEBUG;
|
||||
if(s.equals("INFO")) return Level.INFO;
|
||||
if(s.equals("WARN")) return Level.WARN;
|
||||
if(s.equals("ERROR")) return Level.ERROR;
|
||||
if(s.equals("FATAL")) return Level.FATAL;
|
||||
if(s.equals("OFF")) return Level.OFF;
|
||||
if(s.equals("TRACE")) return Level.TRACE;
|
||||
//
|
||||
// For Turkish i problem, see bug 40937
|
||||
//
|
||||
if(s.equals("\u0130NFO")) return Level.INFO;
|
||||
return defaultLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom deserialization of Level.
|
||||
* @param s serialization stream.
|
||||
* @throws IOException if IO exception.
|
||||
* @throws ClassNotFoundException if class not found.
|
||||
*/
|
||||
private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject();
|
||||
level = s.readInt();
|
||||
syslogEquivalent = s.readInt();
|
||||
levelStr = s.readUTF();
|
||||
if (levelStr == null) {
|
||||
levelStr = "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize level.
|
||||
* @param s serialization stream.
|
||||
* @throws IOException if exception during serialization.
|
||||
*/
|
||||
private void writeObject(final ObjectOutputStream s) throws IOException {
|
||||
s.defaultWriteObject();
|
||||
s.writeInt(level);
|
||||
s.writeInt(syslogEquivalent);
|
||||
s.writeUTF(levelStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolved deserialized level to one of the stock instances.
|
||||
* May be overriden in classes derived from Level.
|
||||
* @return resolved object.
|
||||
* @throws ObjectStreamException if exception during resolution.
|
||||
*/
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
//
|
||||
// if the deserizalized object is exactly an instance of Level
|
||||
//
|
||||
if (getClass() == Level.class) {
|
||||
return toLevel(level);
|
||||
}
|
||||
//
|
||||
// extension of Level can't substitute stock item
|
||||
//
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
1677
java/src/org/apache/log4j/LogMF.java
Normal file
1677
java/src/org/apache/log4j/LogMF.java
Normal file
File diff suppressed because it is too large
Load Diff
276
java/src/org/apache/log4j/LogManager.java
Normal file
276
java/src/org/apache/log4j/LogManager.java
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.LoggerRepository;
|
||||
import org.apache.log4j.spi.LoggerFactory;
|
||||
import org.apache.log4j.spi.RepositorySelector;
|
||||
import org.apache.log4j.spi.DefaultRepositorySelector;
|
||||
import org.apache.log4j.spi.RootLogger;
|
||||
import org.apache.log4j.spi.NOPLoggerRepository;
|
||||
import org.apache.log4j.helpers.Loader;
|
||||
import org.apache.log4j.helpers.OptionConverter;
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.io.StringWriter;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Use the <code>LogManager</code> class to retreive {@link Logger}
|
||||
* instances or to operate on the current {@link
|
||||
* LoggerRepository}. When the <code>LogManager</code> class is loaded
|
||||
* into memory the default initalzation procedure is inititated. The
|
||||
* default intialization procedure</a> is described in the <a
|
||||
* href="../../../../manual.html#defaultInit">short log4j manual</a>.
|
||||
*
|
||||
* @author Ceki Gülcü */
|
||||
public class LogManager {
|
||||
|
||||
/**
|
||||
* @deprecated This variable is for internal use only. It will
|
||||
* become package protected in future versions.
|
||||
* */
|
||||
static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
|
||||
|
||||
static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
|
||||
|
||||
/**
|
||||
* @deprecated This variable is for internal use only. It will
|
||||
* become private in future versions.
|
||||
* */
|
||||
static final public String DEFAULT_CONFIGURATION_KEY="log4j.configuration";
|
||||
|
||||
/**
|
||||
* @deprecated This variable is for internal use only. It will
|
||||
* become private in future versions.
|
||||
* */
|
||||
static final public String CONFIGURATOR_CLASS_KEY="log4j.configuratorClass";
|
||||
|
||||
/**
|
||||
* @deprecated This variable is for internal use only. It will
|
||||
* become private in future versions.
|
||||
*/
|
||||
public static final String DEFAULT_INIT_OVERRIDE_KEY =
|
||||
"log4j.defaultInitOverride";
|
||||
|
||||
|
||||
static private Object guard = null;
|
||||
static private RepositorySelector repositorySelector;
|
||||
|
||||
static {
|
||||
// By default we use a DefaultRepositorySelector which always returns 'h'.
|
||||
Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
|
||||
repositorySelector = new DefaultRepositorySelector(h);
|
||||
|
||||
/** Search for the properties file log4j.properties in the CLASSPATH. */
|
||||
String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
|
||||
null);
|
||||
|
||||
// if there is no default init override, then get the resource
|
||||
// specified by the user or the default config file.
|
||||
if(override == null || "false".equalsIgnoreCase(override)) {
|
||||
|
||||
String configurationOptionStr = OptionConverter.getSystemProperty(
|
||||
DEFAULT_CONFIGURATION_KEY,
|
||||
null);
|
||||
|
||||
String configuratorClassName = OptionConverter.getSystemProperty(
|
||||
CONFIGURATOR_CLASS_KEY,
|
||||
null);
|
||||
|
||||
URL url = null;
|
||||
|
||||
// if the user has not specified the log4j.configuration
|
||||
// property, we search first for the file "log4j.xml" and then
|
||||
// "log4j.properties"
|
||||
if(configurationOptionStr == null) {
|
||||
url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
|
||||
if(url == null) {
|
||||
url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
url = new URL(configurationOptionStr);
|
||||
} catch (MalformedURLException ex) {
|
||||
// so, resource is not a URL:
|
||||
// attempt to get the resource from the class path
|
||||
url = Loader.getResource(configurationOptionStr);
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a non-null url, then delegate the rest of the
|
||||
// configuration to the OptionConverter.selectAndConfigure
|
||||
// method.
|
||||
if(url != null) {
|
||||
LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
|
||||
try {
|
||||
OptionConverter.selectAndConfigure(url, configuratorClassName,
|
||||
LogManager.getLoggerRepository());
|
||||
} catch (NoClassDefFoundError e) {
|
||||
LogLog.warn("Error during default initialization", e);
|
||||
}
|
||||
} else {
|
||||
LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
|
||||
}
|
||||
} else {
|
||||
LogLog.debug("Default initialization of overridden by " +
|
||||
DEFAULT_INIT_OVERRIDE_KEY + "property.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Sets <code>LoggerFactory</code> but only if the correct
|
||||
<em>guard</em> is passed as parameter.
|
||||
|
||||
<p>Initally the guard is null. If the guard is
|
||||
<code>null</code>, then invoking this method sets the logger
|
||||
factory and the guard. Following invocations will throw a {@link
|
||||
IllegalArgumentException}, unless the previously set
|
||||
<code>guard</code> is passed as the second parameter.
|
||||
|
||||
<p>This allows a high-level component to set the {@link
|
||||
RepositorySelector} used by the <code>LogManager</code>.
|
||||
|
||||
<p>For example, when tomcat starts it will be able to install its
|
||||
own repository selector. However, if and when Tomcat is embedded
|
||||
within JBoss, then JBoss will install its own repository selector
|
||||
and Tomcat will use the repository selector set by its container,
|
||||
JBoss. */
|
||||
static
|
||||
public
|
||||
void setRepositorySelector(RepositorySelector selector, Object guard)
|
||||
throws IllegalArgumentException {
|
||||
if((LogManager.guard != null) && (LogManager.guard != guard)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Attempted to reset the LoggerFactory without possessing the guard.");
|
||||
}
|
||||
|
||||
if(selector == null) {
|
||||
throw new IllegalArgumentException("RepositorySelector must be non-null.");
|
||||
}
|
||||
|
||||
LogManager.guard = guard;
|
||||
LogManager.repositorySelector = selector;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method tests if called from a method that
|
||||
* is known to result in class members being abnormally
|
||||
* set to null but is assumed to be harmless since the
|
||||
* all classes are in the process of being unloaded.
|
||||
*
|
||||
* @param ex exception used to determine calling stack.
|
||||
* @return true if calling stack is recognized as likely safe.
|
||||
*/
|
||||
private static boolean isLikelySafeScenario(final Exception ex) {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
ex.printStackTrace(new PrintWriter(stringWriter));
|
||||
String msg = stringWriter.toString();
|
||||
return msg.indexOf("org.apache.catalina.loader.WebappClassLoader.stop") != -1;
|
||||
}
|
||||
|
||||
static
|
||||
public
|
||||
LoggerRepository getLoggerRepository() {
|
||||
if (repositorySelector == null) {
|
||||
repositorySelector = new DefaultRepositorySelector(new NOPLoggerRepository());
|
||||
guard = null;
|
||||
Exception ex = new IllegalStateException("Class invariant violation");
|
||||
String msg =
|
||||
"log4j called after unloading, see http://logging.apache.org/log4j/1.2/faq.html#unload.";
|
||||
if (isLikelySafeScenario(ex)) {
|
||||
LogLog.debug(msg, ex);
|
||||
} else {
|
||||
LogLog.error(msg, ex);
|
||||
}
|
||||
}
|
||||
return repositorySelector.getLoggerRepository();
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieve the appropriate root logger.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Logger getRootLogger() {
|
||||
// Delegate the actual manufacturing of the logger to the logger repository.
|
||||
return getLoggerRepository().getRootLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieve the appropriate {@link Logger} instance.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Logger getLogger(final String name) {
|
||||
// Delegate the actual manufacturing of the logger to the logger repository.
|
||||
return getLoggerRepository().getLogger(name);
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieve the appropriate {@link Logger} instance.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Logger getLogger(final Class clazz) {
|
||||
// Delegate the actual manufacturing of the logger to the logger repository.
|
||||
return getLoggerRepository().getLogger(clazz.getName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Retrieve the appropriate {@link Logger} instance.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Logger getLogger(final String name, final LoggerFactory factory) {
|
||||
// Delegate the actual manufacturing of the logger to the logger repository.
|
||||
return getLoggerRepository().getLogger(name, factory);
|
||||
}
|
||||
|
||||
public
|
||||
static
|
||||
Logger exists(final String name) {
|
||||
return getLoggerRepository().exists(name);
|
||||
}
|
||||
|
||||
public
|
||||
static
|
||||
Enumeration getCurrentLoggers() {
|
||||
return getLoggerRepository().getCurrentLoggers();
|
||||
}
|
||||
|
||||
public
|
||||
static
|
||||
void shutdown() {
|
||||
getLoggerRepository().shutdown();
|
||||
}
|
||||
|
||||
public
|
||||
static
|
||||
void resetConfiguration() {
|
||||
getLoggerRepository().resetConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
1541
java/src/org/apache/log4j/LogSF.java
Normal file
1541
java/src/org/apache/log4j/LogSF.java
Normal file
File diff suppressed because it is too large
Load Diff
371
java/src/org/apache/log4j/LogXF.java
Normal file
371
java/src/org/apache/log4j/LogXF.java
Normal file
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
* This is a base class for LogMF and LogSF parameterized logging classes.
|
||||
*
|
||||
*
|
||||
* @see org.apache.log4j.LogMF
|
||||
* @see org.apache.log4j.LogSF
|
||||
* @since 1.2.16
|
||||
*/
|
||||
public abstract class LogXF {
|
||||
/**
|
||||
* Trace level.
|
||||
*/
|
||||
protected static final Level TRACE = new Level(5000, "TRACE", 7);
|
||||
/**
|
||||
* Fully Qualified Class Name of this class.
|
||||
*/
|
||||
private static final String FQCN = LogXF.class.getName();
|
||||
|
||||
protected LogXF() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Boolean instance representing the specified boolean.
|
||||
* Boolean.valueOf was added in JDK 1.4.
|
||||
*
|
||||
* @param b a boolean value.
|
||||
* @return a Boolean instance representing b.
|
||||
*/
|
||||
protected static Boolean valueOf(final boolean b) {
|
||||
if (b) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Character instance representing the specified char.
|
||||
* Character.valueOf was added in JDK 1.5.
|
||||
*
|
||||
* @param c a character value.
|
||||
* @return a Character instance representing c.
|
||||
*/
|
||||
protected static Character valueOf(final char c) {
|
||||
return new Character(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Byte instance representing the specified byte.
|
||||
* Byte.valueOf was added in JDK 1.5.
|
||||
*
|
||||
* @param b a byte value.
|
||||
* @return a Byte instance representing b.
|
||||
*/
|
||||
protected static Byte valueOf(final byte b) {
|
||||
return new Byte(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Short instance representing the specified short.
|
||||
* Short.valueOf was added in JDK 1.5.
|
||||
*
|
||||
* @param b a short value.
|
||||
* @return a Byte instance representing b.
|
||||
*/
|
||||
protected static Short valueOf(final short b) {
|
||||
return new Short(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Integer instance representing the specified int.
|
||||
* Integer.valueOf was added in JDK 1.5.
|
||||
*
|
||||
* @param b an int value.
|
||||
* @return an Integer instance representing b.
|
||||
*/
|
||||
protected static Integer valueOf(final int b) {
|
||||
return new Integer(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Long instance representing the specified long.
|
||||
* Long.valueOf was added in JDK 1.5.
|
||||
*
|
||||
* @param b a long value.
|
||||
* @return a Long instance representing b.
|
||||
*/
|
||||
protected static Long valueOf(final long b) {
|
||||
return new Long(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Float instance representing the specified float.
|
||||
* Float.valueOf was added in JDK 1.5.
|
||||
*
|
||||
* @param b a float value.
|
||||
* @return a Float instance representing b.
|
||||
*/
|
||||
protected static Float valueOf(final float b) {
|
||||
return new Float(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Double instance representing the specified double.
|
||||
* Double.valueOf was added in JDK 1.5.
|
||||
*
|
||||
* @param b a double value.
|
||||
* @return a Byte instance representing b.
|
||||
*/
|
||||
protected static Double valueOf(final double b) {
|
||||
return new Double(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new array.
|
||||
*
|
||||
* @param param1 parameter 1.
|
||||
* @return new array.
|
||||
*/
|
||||
protected static Object[] toArray(final Object param1) {
|
||||
return new Object[]{
|
||||
param1
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new array.
|
||||
*
|
||||
* @param param1 parameter 1.
|
||||
* @param param2 parameter 2.
|
||||
* @return new array.
|
||||
*/
|
||||
protected static Object[] toArray(final Object param1,
|
||||
final Object param2) {
|
||||
return new Object[]{
|
||||
param1, param2
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new array.
|
||||
*
|
||||
* @param param1 parameter 1.
|
||||
* @param param2 parameter 2.
|
||||
* @param param3 parameter 3.
|
||||
* @return new array.
|
||||
*/
|
||||
protected static Object[] toArray(final Object param1,
|
||||
final Object param2,
|
||||
final Object param3) {
|
||||
return new Object[]{
|
||||
param1, param2, param3
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new array.
|
||||
*
|
||||
* @param param1 parameter 1.
|
||||
* @param param2 parameter 2.
|
||||
* @param param3 parameter 3.
|
||||
* @param param4 parameter 4.
|
||||
* @return new array.
|
||||
*/
|
||||
protected static Object[] toArray(final Object param1,
|
||||
final Object param2,
|
||||
final Object param3,
|
||||
final Object param4) {
|
||||
return new Object[]{
|
||||
param1, param2, param3, param4
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an entering message at DEBUG level.
|
||||
*
|
||||
* @param logger logger, may not be null.
|
||||
* @param sourceClass source class, may be null.
|
||||
* @param sourceMethod method, may be null.
|
||||
*/
|
||||
public static void entering(final Logger logger,
|
||||
final String sourceClass,
|
||||
final String sourceMethod) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
||||
sourceClass + "." + sourceMethod + " ENTRY", null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an entering message with a parameter at DEBUG level.
|
||||
*
|
||||
* @param logger logger, may not be null.
|
||||
* @param sourceClass source class, may be null.
|
||||
* @param sourceMethod method, may be null.
|
||||
* @param param parameter, may be null.
|
||||
*/
|
||||
public static void entering(final Logger logger,
|
||||
final String sourceClass,
|
||||
final String sourceMethod,
|
||||
final String param) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
String msg = sourceClass + "." + sourceMethod + " ENTRY " + param;
|
||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
||||
msg, null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an entering message with a parameter at DEBUG level.
|
||||
*
|
||||
* @param logger logger, may not be null.
|
||||
* @param sourceClass source class, may be null.
|
||||
* @param sourceMethod method, may be null.
|
||||
* @param param parameter, may be null.
|
||||
*/
|
||||
public static void entering(final Logger logger,
|
||||
final String sourceClass,
|
||||
final String sourceMethod,
|
||||
final Object param) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
String msg = sourceClass + "." + sourceMethod + " ENTRY ";
|
||||
if (param == null) {
|
||||
msg += "null";
|
||||
} else {
|
||||
try {
|
||||
msg += param;
|
||||
} catch(Throwable ex) {
|
||||
msg += "?";
|
||||
}
|
||||
}
|
||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
||||
msg, null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an entering message with an array of parameters at DEBUG level.
|
||||
*
|
||||
* @param logger logger, may not be null.
|
||||
* @param sourceClass source class, may be null.
|
||||
* @param sourceMethod method, may be null.
|
||||
* @param params parameters, may be null.
|
||||
*/
|
||||
public static void entering(final Logger logger,
|
||||
final String sourceClass,
|
||||
final String sourceMethod,
|
||||
final Object[] params) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
String msg = sourceClass + "." + sourceMethod + " ENTRY ";
|
||||
if (params != null && params.length > 0) {
|
||||
String delim = "{";
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
try {
|
||||
msg += delim + params[i];
|
||||
} catch(Throwable ex) {
|
||||
msg += delim + "?";
|
||||
}
|
||||
delim = ",";
|
||||
}
|
||||
msg += "}";
|
||||
} else {
|
||||
msg += "{}";
|
||||
}
|
||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
||||
msg, null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an exiting message at DEBUG level.
|
||||
*
|
||||
* @param logger logger, may not be null.
|
||||
* @param sourceClass source class, may be null.
|
||||
* @param sourceMethod method, may be null.
|
||||
*/
|
||||
public static void exiting(final Logger logger,
|
||||
final String sourceClass,
|
||||
final String sourceMethod) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
||||
sourceClass + "." + sourceMethod + " RETURN", null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an exiting message with result at DEBUG level.
|
||||
*
|
||||
* @param logger logger, may not be null.
|
||||
* @param sourceClass source class, may be null.
|
||||
* @param sourceMethod method, may be null.
|
||||
* @param result result, may be null.
|
||||
*/
|
||||
public static void exiting(
|
||||
final Logger logger,
|
||||
final String sourceClass,
|
||||
final String sourceMethod,
|
||||
final String result) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
||||
sourceClass + "." + sourceMethod + " RETURN " + result, null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an exiting message with result at DEBUG level.
|
||||
*
|
||||
* @param logger logger, may not be null.
|
||||
* @param sourceClass source class, may be null.
|
||||
* @param sourceMethod method, may be null.
|
||||
* @param result result, may be null.
|
||||
*/
|
||||
public static void exiting(
|
||||
final Logger logger,
|
||||
final String sourceClass,
|
||||
final String sourceMethod,
|
||||
final Object result) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
String msg = sourceClass + "." + sourceMethod + " RETURN ";
|
||||
if (result == null) {
|
||||
msg += "null";
|
||||
} else {
|
||||
try {
|
||||
msg += result;
|
||||
} catch(Throwable ex) {
|
||||
msg += "?";
|
||||
}
|
||||
}
|
||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
||||
msg, null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a throwing message at DEBUG level.
|
||||
*
|
||||
* @param logger logger, may not be null.
|
||||
* @param sourceClass source class, may be null.
|
||||
* @param sourceMethod method, may be null.
|
||||
* @param thrown throwable, may be null.
|
||||
*/
|
||||
public static void throwing(
|
||||
final Logger logger,
|
||||
final String sourceClass,
|
||||
final String sourceMethod,
|
||||
final Throwable thrown) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.callAppenders(new LoggingEvent(FQCN, logger, Level.DEBUG,
|
||||
sourceClass + "." + sourceMethod + " THROW", thrown));
|
||||
}
|
||||
}
|
||||
}
|
||||
212
java/src/org/apache/log4j/Logger.java
Normal file
212
java/src/org/apache/log4j/Logger.java
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
This is the central class in the log4j package. Most logging
|
||||
operations, except configuration, are done through this class.
|
||||
|
||||
@since log4j 1.2
|
||||
|
||||
@author Ceki Gülcü */
|
||||
public class Logger extends Category {
|
||||
|
||||
/**
|
||||
The fully qualified name of the Logger class. See also the
|
||||
getFQCN method. */
|
||||
private static final String FQCN = Logger.class.getName();
|
||||
|
||||
|
||||
protected
|
||||
Logger(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
Log a message object with the {@link Level#FINE FINE} level which
|
||||
is just an alias for the {@link Level#DEBUG DEBUG} level.
|
||||
|
||||
<p>This method first checks if this category is <code>DEBUG</code>
|
||||
enabled by comparing the level of this category with the {@link
|
||||
Level#DEBUG DEBUG} level. If this category is
|
||||
<code>DEBUG</code> enabled, then it converts the message object
|
||||
(passed as parameter) to a string by invoking the appropriate
|
||||
{@link org.apache.log4j.or.ObjectRenderer}. It then proceeds to call all the
|
||||
registered appenders in this category and also higher in the
|
||||
hierarchy depending on the value of the additivity flag.
|
||||
|
||||
<p><b>WARNING</b> Note that passing a {@link Throwable} to this
|
||||
method will print the name of the <code>Throwable</code> but no
|
||||
stack trace. To print a stack trace use the {@link #debug(Object,
|
||||
Throwable)} form instead.
|
||||
|
||||
@param message the message object to log. */
|
||||
//public
|
||||
//void fine(Object message) {
|
||||
// if(repository.isDisabled(Level.DEBUG_INT))
|
||||
// return;
|
||||
// if(Level.DEBUG.isGreaterOrEqual(this.getChainedLevel())) {
|
||||
// forcedLog(FQCN, Level.DEBUG, message, null);
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
/**
|
||||
Log a message object with the <code>FINE</code> level including
|
||||
the stack trace of the {@link Throwable} <code>t</code> passed as
|
||||
parameter.
|
||||
|
||||
<p>See {@link #fine(Object)} form for more detailed information.
|
||||
|
||||
@param message the message object to log.
|
||||
@param t the exception to log, including its stack trace. */
|
||||
//public
|
||||
//void fine(Object message, Throwable t) {
|
||||
// if(repository.isDisabled(Level.DEBUG_INT))
|
||||
// return;
|
||||
// if(Level.DEBUG.isGreaterOrEqual(this.getChainedLevel()))
|
||||
// forcedLog(FQCN, Level.FINE, message, t);
|
||||
//}
|
||||
|
||||
/**
|
||||
* Retrieve a logger named according to the value of the
|
||||
* <code>name</code> parameter. If the named logger already exists,
|
||||
* then the existing instance will be returned. Otherwise, a new
|
||||
* instance is created.
|
||||
*
|
||||
* <p>By default, loggers do not have a set level but inherit it
|
||||
* from their neareast ancestor with a set level. This is one of the
|
||||
* central features of log4j.
|
||||
*
|
||||
* @param name The name of the logger to retrieve.
|
||||
*/
|
||||
static
|
||||
public
|
||||
Logger getLogger(String name) {
|
||||
return LogManager.getLogger(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorthand for <code>getLogger(clazz.getName())</code>.
|
||||
*
|
||||
* @param clazz The name of <code>clazz</code> will be used as the
|
||||
* name of the logger to retrieve. See {@link #getLogger(String)}
|
||||
* for more detailed information.
|
||||
*/
|
||||
static
|
||||
public
|
||||
Logger getLogger(Class clazz) {
|
||||
return LogManager.getLogger(clazz.getName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the root logger for the current logger repository.
|
||||
* <p>
|
||||
* The {@link #getName Logger.getName()} method for the root logger always returns
|
||||
* stirng value: "root". However, calling
|
||||
* <code>Logger.getLogger("root")</code> does not retrieve the root
|
||||
* logger but a logger just under root named "root".
|
||||
* <p>
|
||||
* In other words, calling this method is the only way to retrieve the
|
||||
* root logger.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Logger getRootLogger() {
|
||||
return LogManager.getRootLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
Like {@link #getLogger(String)} except that the type of logger
|
||||
instantiated depends on the type returned by the {@link
|
||||
LoggerFactory#makeNewLoggerInstance} method of the
|
||||
<code>factory</code> parameter.
|
||||
|
||||
<p>This method is intended to be used by sub-classes.
|
||||
|
||||
@param name The name of the logger to retrieve.
|
||||
|
||||
@param factory A {@link LoggerFactory} implementation that will
|
||||
actually create a new Instance.
|
||||
|
||||
@since 0.8.5 */
|
||||
public
|
||||
static
|
||||
Logger getLogger(String name, LoggerFactory factory) {
|
||||
return LogManager.getLogger(name, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message object with the {@link org.apache.log4j.Level#TRACE TRACE} level.
|
||||
*
|
||||
* @param message the message object to log.
|
||||
* @see #debug(Object) for an explanation of the logic applied.
|
||||
* @since 1.2.12
|
||||
*/
|
||||
public void trace(Object message) {
|
||||
if (repository.isDisabled(Level.TRACE_INT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel())) {
|
||||
forcedLog(FQCN, Level.TRACE, message, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message object with the <code>TRACE</code> level including the
|
||||
* stack trace of the {@link Throwable}<code>t</code> passed as parameter.
|
||||
*
|
||||
* <p>
|
||||
* See {@link #debug(Object)} form for more detailed information.
|
||||
* </p>
|
||||
*
|
||||
* @param message the message object to log.
|
||||
* @param t the exception to log, including its stack trace.
|
||||
* @since 1.2.12
|
||||
*/
|
||||
public void trace(Object message, Throwable t) {
|
||||
if (repository.isDisabled(Level.TRACE_INT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel())) {
|
||||
forcedLog(FQCN, Level.TRACE, message, t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this category is enabled for the TRACE Level.
|
||||
* @since 1.2.12
|
||||
*
|
||||
* @return boolean - <code>true</code> if this category is enabled for level
|
||||
* TRACE, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isTraceEnabled() {
|
||||
if (repository.isDisabled(Level.TRACE_INT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Level.TRACE.isGreaterOrEqual(this.getEffectiveLevel());
|
||||
}
|
||||
|
||||
}
|
||||
187
java/src/org/apache/log4j/MDC.java
Normal file
187
java/src/org/apache/log4j/MDC.java
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import org.apache.log4j.helpers.Loader;
|
||||
import org.apache.log4j.helpers.ThreadLocalMap;
|
||||
|
||||
/**
|
||||
The MDC class is similar to the {@link NDC} class except that it is
|
||||
based on a map instead of a stack. It provides <em>mapped
|
||||
diagnostic contexts</em>. A <em>Mapped Diagnostic Context</em>, or
|
||||
MDC in short, is an instrument for distinguishing interleaved log
|
||||
output from different sources. Log output is typically interleaved
|
||||
when a server handles multiple clients near-simultaneously.
|
||||
|
||||
<p><b><em>The MDC is managed on a per thread basis</em></b>. A
|
||||
child thread automatically inherits a <em>copy</em> of the mapped
|
||||
diagnostic context of its parent.
|
||||
|
||||
<p>The MDC class requires JDK 1.2 or above. Under JDK 1.1 the MDC
|
||||
will always return empty values but otherwise will not affect or
|
||||
harm your application.
|
||||
|
||||
@since 1.2
|
||||
|
||||
@author Ceki Gülcü */
|
||||
public class MDC {
|
||||
|
||||
final static MDC mdc = new MDC();
|
||||
|
||||
static final int HT_SIZE = 7;
|
||||
|
||||
boolean java1;
|
||||
|
||||
Object tlm;
|
||||
|
||||
private
|
||||
MDC() {
|
||||
java1 = Loader.isJava1();
|
||||
if(!java1) {
|
||||
tlm = new ThreadLocalMap();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Put a context value (the <code>o</code> parameter) as identified
|
||||
with the <code>key</code> parameter into the current thread's
|
||||
context map.
|
||||
|
||||
<p>If the current thread does not have a context map it is
|
||||
created as a side effect.
|
||||
|
||||
*/
|
||||
static
|
||||
public
|
||||
void put(String key, Object o) {
|
||||
if (mdc != null) {
|
||||
mdc.put0(key, o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Get the context identified by the <code>key</code> parameter.
|
||||
|
||||
<p>This method has no side effects.
|
||||
*/
|
||||
static
|
||||
public
|
||||
Object get(String key) {
|
||||
if (mdc != null) {
|
||||
return mdc.get0(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
Remove the the context identified by the <code>key</code>
|
||||
parameter.
|
||||
|
||||
*/
|
||||
static
|
||||
public
|
||||
void remove(String key) {
|
||||
if (mdc != null) {
|
||||
mdc.remove0(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the current thread's MDC as a hashtable. This method is
|
||||
* intended to be used internally.
|
||||
* */
|
||||
public static Hashtable getContext() {
|
||||
if (mdc != null) {
|
||||
return mdc.getContext0();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all values from the MDC.
|
||||
* @since 1.2.16
|
||||
*/
|
||||
public static void clear() {
|
||||
if (mdc != null) {
|
||||
mdc.clear0();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private
|
||||
void put0(String key, Object o) {
|
||||
if(java1 || tlm == null) {
|
||||
return;
|
||||
} else {
|
||||
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
|
||||
if(ht == null) {
|
||||
ht = new Hashtable(HT_SIZE);
|
||||
((ThreadLocalMap)tlm).set(ht);
|
||||
}
|
||||
ht.put(key, o);
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
Object get0(String key) {
|
||||
if(java1 || tlm == null) {
|
||||
return null;
|
||||
} else {
|
||||
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
|
||||
if(ht != null && key != null) {
|
||||
return ht.get(key);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
void remove0(String key) {
|
||||
if(!java1 && tlm != null) {
|
||||
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
|
||||
if(ht != null) {
|
||||
ht.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private
|
||||
Hashtable getContext0() {
|
||||
if(java1 || tlm == null) {
|
||||
return null;
|
||||
} else {
|
||||
return (Hashtable) ((ThreadLocalMap)tlm).get();
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
void clear0() {
|
||||
if(!java1 && tlm != null) {
|
||||
Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
|
||||
if(ht != null) {
|
||||
ht.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
436
java/src/org/apache/log4j/NDC.java
Normal file
436
java/src/org/apache/log4j/NDC.java
Normal file
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
// Contributors: Dan Milstein
|
||||
// Ray Millard
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Stack;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
|
||||
/**
|
||||
The NDC class implements <i>nested diagnostic contexts</i> as
|
||||
defined by Neil Harrison in the article "Patterns for Logging
|
||||
Diagnostic Messages" part of the book "<i>Pattern Languages of
|
||||
Program Design 3</i>" edited by Martin et al.
|
||||
|
||||
<p>A Nested Diagnostic Context, or NDC in short, is an instrument
|
||||
to distinguish interleaved log output from different sources. Log
|
||||
output is typically interleaved when a server handles multiple
|
||||
clients near-simultaneously.
|
||||
|
||||
<p>Interleaved log output can still be meaningful if each log entry
|
||||
from different contexts had a distinctive stamp. This is where NDCs
|
||||
come into play.
|
||||
|
||||
<p><em><b>Note that NDCs are managed on a per thread
|
||||
basis</b></em>. NDC operations such as {@link #push push}, {@link
|
||||
#pop}, {@link #clear}, {@link #getDepth} and {@link #setMaxDepth}
|
||||
affect the NDC of the <em>current</em> thread only. NDCs of other
|
||||
threads remain unaffected.
|
||||
|
||||
<p>For example, a servlet can build a per client request NDC
|
||||
consisting the clients host name and other information contained in
|
||||
the the request. <em>Cookies</em> are another source of distinctive
|
||||
information. To build an NDC one uses the {@link #push push}
|
||||
operation. Simply put,
|
||||
|
||||
<p><ul>
|
||||
<li>Contexts can be nested.
|
||||
|
||||
<p><li>When entering a context, call <code>NDC.push</code>. As a
|
||||
side effect, if there is no nested diagnostic context for the
|
||||
current thread, this method will create it.
|
||||
|
||||
<p><li>When leaving a context, call <code>NDC.pop</code>.
|
||||
|
||||
<p><li><b>When exiting a thread make sure to call {@link #remove
|
||||
NDC.remove()}</b>.
|
||||
</ul>
|
||||
|
||||
<p>There is no penalty for forgetting to match each
|
||||
<code>push</code> operation with a corresponding <code>pop</code>,
|
||||
except the obvious mismatch between the real application context
|
||||
and the context set in the NDC.
|
||||
|
||||
<p>If configured to do so, {@link PatternLayout} and {@link
|
||||
TTCCLayout} instances automatically retrieve the nested diagnostic
|
||||
context for the current thread without any user intervention.
|
||||
Hence, even if a servlet is serving multiple clients
|
||||
simultaneously, the logs emanating from the same code (belonging to
|
||||
the same category) can still be distinguished because each client
|
||||
request will have a different NDC tag.
|
||||
|
||||
<p>Heavy duty systems should call the {@link #remove} method when
|
||||
leaving the run method of a thread. This ensures that the memory
|
||||
used by the thread can be freed by the Java garbage
|
||||
collector. There is a mechanism to lazily remove references to dead
|
||||
threads. In practice, this means that you can be a little sloppy
|
||||
and sometimes forget to call {@link #remove} before exiting a
|
||||
thread.
|
||||
|
||||
<p>A thread may inherit the nested diagnostic context of another
|
||||
(possibly parent) thread using the {@link #inherit inherit}
|
||||
method. A thread may obtain a copy of its NDC with the {@link
|
||||
#cloneStack cloneStack} method and pass the reference to any other
|
||||
thread, in particular to a child.
|
||||
|
||||
@author Ceki Gülcü
|
||||
@since 0.7.0
|
||||
|
||||
*/
|
||||
|
||||
public class NDC {
|
||||
|
||||
// The synchronized keyword is not used in this class. This may seem
|
||||
// dangerous, especially since the class will be used by
|
||||
// multiple-threads. In particular, all threads share the same
|
||||
// hashtable (the "ht" variable). This is OK since java hashtables
|
||||
// are thread safe. Same goes for Stacks.
|
||||
|
||||
// More importantly, when inheriting diagnostic contexts the child
|
||||
// thread is handed a clone of the parent's NDC. It follows that
|
||||
// each thread has its own NDC (i.e. stack).
|
||||
|
||||
static Hashtable ht = new Hashtable();
|
||||
|
||||
static int pushCounter = 0; // the number of times push has been called
|
||||
// after the latest call to lazyRemove
|
||||
|
||||
// The number of times we allow push to be called before we call lazyRemove
|
||||
// 5 is a relatively small number. As such, lazyRemove is not called too
|
||||
// frequently. We thus avoid the cost of creating an Enumeration too often.
|
||||
// The higher this number, the longer is the avarage period for which all
|
||||
// logging calls in all threads are blocked.
|
||||
static final int REAP_THRESHOLD = 5;
|
||||
|
||||
// No instances allowed.
|
||||
private NDC() {}
|
||||
|
||||
/**
|
||||
* Get NDC stack for current thread.
|
||||
* @return NDC stack for current thread.
|
||||
*/
|
||||
private static Stack getCurrentStack() {
|
||||
if (ht != null) {
|
||||
return (Stack) ht.get(Thread.currentThread());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Clear any nested diagnostic information if any. This method is
|
||||
useful in cases where the same thread can be potentially used
|
||||
over and over in different unrelated contexts.
|
||||
|
||||
<p>This method is equivalent to calling the {@link #setMaxDepth}
|
||||
method with a zero <code>maxDepth</code> argument.
|
||||
|
||||
@since 0.8.4c */
|
||||
public
|
||||
static
|
||||
void clear() {
|
||||
Stack stack = getCurrentStack();
|
||||
if(stack != null)
|
||||
stack.setSize(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Clone the diagnostic context for the current thread.
|
||||
|
||||
<p>Internally a diagnostic context is represented as a stack. A
|
||||
given thread can supply the stack (i.e. diagnostic context) to a
|
||||
child thread so that the child can inherit the parent thread's
|
||||
diagnostic context.
|
||||
|
||||
<p>The child thread uses the {@link #inherit inherit} method to
|
||||
inherit the parent's diagnostic context.
|
||||
|
||||
@return Stack A clone of the current thread's diagnostic context.
|
||||
|
||||
*/
|
||||
public
|
||||
static
|
||||
Stack cloneStack() {
|
||||
Stack stack = getCurrentStack();
|
||||
if(stack == null)
|
||||
return null;
|
||||
else {
|
||||
return (Stack) stack.clone();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Inherit the diagnostic context of another thread.
|
||||
|
||||
<p>The parent thread can obtain a reference to its diagnostic
|
||||
context using the {@link #cloneStack} method. It should
|
||||
communicate this information to its child so that it may inherit
|
||||
the parent's diagnostic context.
|
||||
|
||||
<p>The parent's diagnostic context is cloned before being
|
||||
inherited. In other words, once inherited, the two diagnostic
|
||||
contexts can be managed independently.
|
||||
|
||||
<p>In java, a child thread cannot obtain a reference to its
|
||||
parent, unless it is directly handed the reference. Consequently,
|
||||
there is no client-transparent way of inheriting diagnostic
|
||||
contexts. Do you know any solution to this problem?
|
||||
|
||||
@param stack The diagnostic context of the parent thread.
|
||||
|
||||
*/
|
||||
public
|
||||
static
|
||||
void inherit(Stack stack) {
|
||||
if(stack != null)
|
||||
ht.put(Thread.currentThread(), stack);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
<font color="#FF4040"><b>Never use this method directly, use the {@link
|
||||
org.apache.log4j.spi.LoggingEvent#getNDC} method instead</b></font>.
|
||||
*/
|
||||
static
|
||||
public
|
||||
String get() {
|
||||
Stack s = getCurrentStack();
|
||||
if(s != null && !s.isEmpty())
|
||||
return ((DiagnosticContext) s.peek()).fullMessage;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current nesting depth of this diagnostic context.
|
||||
*
|
||||
* @see #setMaxDepth
|
||||
* @since 0.7.5
|
||||
*/
|
||||
public
|
||||
static
|
||||
int getDepth() {
|
||||
Stack stack = getCurrentStack();
|
||||
if(stack == null)
|
||||
return 0;
|
||||
else
|
||||
return stack.size();
|
||||
}
|
||||
|
||||
private
|
||||
static
|
||||
void lazyRemove() {
|
||||
if (ht == null) return;
|
||||
|
||||
// The synchronization on ht is necessary to prevent JDK 1.2.x from
|
||||
// throwing ConcurrentModificationExceptions at us. This sucks BIG-TIME.
|
||||
// One solution is to write our own hashtable implementation.
|
||||
Vector v;
|
||||
|
||||
synchronized(ht) {
|
||||
// Avoid calling clean-up too often.
|
||||
if(++pushCounter <= REAP_THRESHOLD) {
|
||||
return; // We release the lock ASAP.
|
||||
} else {
|
||||
pushCounter = 0; // OK let's do some work.
|
||||
}
|
||||
|
||||
int misses = 0;
|
||||
v = new Vector();
|
||||
Enumeration enumeration = ht.keys();
|
||||
// We give up after 4 straigt missses. That is 4 consecutive
|
||||
// inspected threads in 'ht' that turn out to be alive.
|
||||
// The higher the proportion on dead threads in ht, the higher the
|
||||
// chances of removal.
|
||||
while(enumeration.hasMoreElements() && (misses <= 4)) {
|
||||
Thread t = (Thread) enumeration.nextElement();
|
||||
if(t.isAlive()) {
|
||||
misses++;
|
||||
} else {
|
||||
misses = 0;
|
||||
v.addElement(t);
|
||||
}
|
||||
}
|
||||
} // synchronized
|
||||
|
||||
int size = v.size();
|
||||
for(int i = 0; i < size; i++) {
|
||||
Thread t = (Thread) v.elementAt(i);
|
||||
LogLog.debug("Lazy NDC removal for thread [" + t.getName() + "] ("+
|
||||
ht.size() + ").");
|
||||
ht.remove(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Clients should call this method before leaving a diagnostic
|
||||
context.
|
||||
|
||||
<p>The returned value is the value that was pushed last. If no
|
||||
context is available, then the empty string "" is returned.
|
||||
|
||||
@return String The innermost diagnostic context.
|
||||
|
||||
*/
|
||||
public
|
||||
static
|
||||
String pop() {
|
||||
Stack stack = getCurrentStack();
|
||||
if(stack != null && !stack.isEmpty())
|
||||
return ((DiagnosticContext) stack.pop()).message;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
Looks at the last diagnostic context at the top of this NDC
|
||||
without removing it.
|
||||
|
||||
<p>The returned value is the value that was pushed last. If no
|
||||
context is available, then the empty string "" is returned.
|
||||
|
||||
@return String The innermost diagnostic context.
|
||||
|
||||
*/
|
||||
public
|
||||
static
|
||||
String peek() {
|
||||
Stack stack = getCurrentStack();
|
||||
if(stack != null && !stack.isEmpty())
|
||||
return ((DiagnosticContext) stack.peek()).message;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
Push new diagnostic context information for the current thread.
|
||||
|
||||
<p>The contents of the <code>message</code> parameter is
|
||||
determined solely by the client.
|
||||
|
||||
@param message The new diagnostic context information. */
|
||||
public
|
||||
static
|
||||
void push(String message) {
|
||||
Stack stack = getCurrentStack();
|
||||
|
||||
if(stack == null) {
|
||||
DiagnosticContext dc = new DiagnosticContext(message, null);
|
||||
stack = new Stack();
|
||||
Thread key = Thread.currentThread();
|
||||
ht.put(key, stack);
|
||||
stack.push(dc);
|
||||
} else if (stack.isEmpty()) {
|
||||
DiagnosticContext dc = new DiagnosticContext(message, null);
|
||||
stack.push(dc);
|
||||
} else {
|
||||
DiagnosticContext parent = (DiagnosticContext) stack.peek();
|
||||
stack.push(new DiagnosticContext(message, parent));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Remove the diagnostic context for this thread.
|
||||
|
||||
<p>Each thread that created a diagnostic context by calling
|
||||
{@link #push} should call this method before exiting. Otherwise,
|
||||
the memory used by the <b>thread</b> cannot be reclaimed by the
|
||||
VM.
|
||||
|
||||
<p>As this is such an important problem in heavy duty systems and
|
||||
because it is difficult to always guarantee that the remove
|
||||
method is called before exiting a thread, this method has been
|
||||
augmented to lazily remove references to dead threads. In
|
||||
practice, this means that you can be a little sloppy and
|
||||
occasionally forget to call {@link #remove} before exiting a
|
||||
thread. However, you must call <code>remove</code> sometime. If
|
||||
you never call it, then your application is sure to run out of
|
||||
memory.
|
||||
|
||||
*/
|
||||
static
|
||||
public
|
||||
void remove() {
|
||||
if (ht != null) {
|
||||
ht.remove(Thread.currentThread());
|
||||
|
||||
// Lazily remove dead-thread references in ht.
|
||||
lazyRemove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Set maximum depth of this diagnostic context. If the current
|
||||
depth is smaller or equal to <code>maxDepth</code>, then no
|
||||
action is taken.
|
||||
|
||||
<p>This method is a convenient alternative to multiple {@link
|
||||
#pop} calls. Moreover, it is often the case that at the end of
|
||||
complex call sequences, the depth of the NDC is
|
||||
unpredictable. The <code>setMaxDepth</code> method circumvents
|
||||
this problem.
|
||||
|
||||
<p>For example, the combination
|
||||
<pre>
|
||||
void foo() {
|
||||
int depth = NDC.getDepth();
|
||||
|
||||
... complex sequence of calls
|
||||
|
||||
NDC.setMaxDepth(depth);
|
||||
}
|
||||
</pre>
|
||||
|
||||
ensures that between the entry and exit of foo the depth of the
|
||||
diagnostic stack is conserved.
|
||||
|
||||
@see #getDepth
|
||||
@since 0.7.5 */
|
||||
static
|
||||
public
|
||||
void setMaxDepth(int maxDepth) {
|
||||
Stack stack = getCurrentStack();
|
||||
if(stack != null && maxDepth < stack.size())
|
||||
stack.setSize(maxDepth);
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
private static class DiagnosticContext {
|
||||
|
||||
String fullMessage;
|
||||
String message;
|
||||
|
||||
DiagnosticContext(String message, DiagnosticContext parent) {
|
||||
this.message = message;
|
||||
if(parent != null) {
|
||||
fullMessage = parent.fullMessage + ' ' + message;
|
||||
} else {
|
||||
fullMessage = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
511
java/src/org/apache/log4j/PatternLayout.java
Normal file
511
java/src/org/apache/log4j/PatternLayout.java
Normal file
@@ -0,0 +1,511 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
import org.apache.log4j.helpers.PatternParser;
|
||||
import org.apache.log4j.helpers.PatternConverter;
|
||||
|
||||
|
||||
// Contributors: Nelson Minar <nelson@monkey.org>
|
||||
// Anders Kristensen <akristensen@dynamicsoft.com>
|
||||
|
||||
/**
|
||||
|
||||
A flexible layout configurable with pattern string.
|
||||
|
||||
This code is known to have synchronization and other issues
|
||||
which are not present in org.apache.log4j.EnhancedPatternLayout.
|
||||
EnhancedPatternLayout should be used in preference to PatternLayout.
|
||||
EnhancedPatternLayout is distributed in the log4j extras companion.
|
||||
|
||||
<p>The goal of this class is to {@link #format format} a {@link
|
||||
LoggingEvent} and return the results as a String. The results
|
||||
depend on the <em>conversion pattern</em>.
|
||||
|
||||
<p>The conversion pattern is closely related to the conversion
|
||||
pattern of the printf function in C. A conversion pattern is
|
||||
composed of literal text and format control expressions called
|
||||
<em>conversion specifiers</em>.
|
||||
|
||||
<p><i>You are free to insert any literal text within the conversion
|
||||
pattern.</i>
|
||||
|
||||
<p>Each conversion specifier starts with a percent sign (%) and is
|
||||
followed by optional <em>format modifiers</em> and a <em>conversion
|
||||
character</em>. The conversion character specifies the type of
|
||||
data, e.g. category, priority, date, thread name. The format
|
||||
modifiers control such things as field width, padding, left and
|
||||
right justification. The following is a simple example.
|
||||
|
||||
<p>Let the conversion pattern be <b>"%-5p [%t]: %m%n"</b> and assume
|
||||
that the log4j environment was set to use a PatternLayout. Then the
|
||||
statements
|
||||
<pre>
|
||||
Category root = Category.getRoot();
|
||||
root.debug("Message 1");
|
||||
root.warn("Message 2");
|
||||
</pre>
|
||||
would yield the output
|
||||
<pre>
|
||||
DEBUG [main]: Message 1
|
||||
WARN [main]: Message 2
|
||||
</pre>
|
||||
|
||||
<p>Note that there is no explicit separator between text and
|
||||
conversion specifiers. The pattern parser knows when it has reached
|
||||
the end of a conversion specifier when it reads a conversion
|
||||
character. In the example above the conversion specifier
|
||||
<b>%-5p</b> means the priority of the logging event should be left
|
||||
justified to a width of five characters.
|
||||
|
||||
The recognized conversion characters are
|
||||
|
||||
<p>
|
||||
<table border="1" CELLPADDING="8">
|
||||
<th>Conversion Character</th>
|
||||
<th>Effect</th>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>c</b></td>
|
||||
|
||||
<td>Used to output the category of the logging event. The
|
||||
category conversion specifier can be optionally followed by
|
||||
<em>precision specifier</em>, that is a decimal constant in
|
||||
brackets.
|
||||
|
||||
<p>If a precision specifier is given, then only the corresponding
|
||||
number of right most components of the category name will be
|
||||
printed. By default the category name is printed in full.
|
||||
|
||||
<p>For example, for the category name "a.b.c" the pattern
|
||||
<b>%c{2}</b> will output "b.c".
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>C</b></td>
|
||||
|
||||
<td>Used to output the fully qualified class name of the caller
|
||||
issuing the logging request. This conversion specifier
|
||||
can be optionally followed by <em>precision specifier</em>, that
|
||||
is a decimal constant in brackets.
|
||||
|
||||
<p>If a precision specifier is given, then only the corresponding
|
||||
number of right most components of the class name will be
|
||||
printed. By default the class name is output in fully qualified form.
|
||||
|
||||
<p>For example, for the class name "org.apache.xyz.SomeClass", the
|
||||
pattern <b>%C{1}</b> will output "SomeClass".
|
||||
|
||||
<p><b>WARNING</b> Generating the caller class information is
|
||||
slow. Thus, use should be avoided unless execution speed is
|
||||
not an issue.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr> <td align=center><b>d</b></td> <td>Used to output the date of
|
||||
the logging event. The date conversion specifier may be
|
||||
followed by a <em>date format specifier</em> enclosed between
|
||||
braces. For example, <b>%d{HH:mm:ss,SSS}</b> or
|
||||
<b>%d{dd MMM yyyy HH:mm:ss,SSS}</b>. If no
|
||||
date format specifier is given then ISO8601 format is
|
||||
assumed.
|
||||
|
||||
<p>The date format specifier admits the same syntax as the
|
||||
time pattern string of the {@link
|
||||
java.text.SimpleDateFormat}. Although part of the standard
|
||||
JDK, the performance of <code>SimpleDateFormat</code> is
|
||||
quite poor.
|
||||
|
||||
<p>For better results it is recommended to use the log4j date
|
||||
formatters. These can be specified using one of the strings
|
||||
"ABSOLUTE", "DATE" and "ISO8601" for specifying {@link
|
||||
org.apache.log4j.helpers.AbsoluteTimeDateFormat
|
||||
AbsoluteTimeDateFormat}, {@link
|
||||
org.apache.log4j.helpers.DateTimeDateFormat DateTimeDateFormat}
|
||||
and respectively {@link
|
||||
org.apache.log4j.helpers.ISO8601DateFormat
|
||||
ISO8601DateFormat}. For example, <b>%d{ISO8601}</b> or
|
||||
<b>%d{ABSOLUTE}</b>.
|
||||
|
||||
<p>These dedicated date formatters perform significantly
|
||||
better than {@link java.text.SimpleDateFormat}.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>F</b></td>
|
||||
|
||||
<td>Used to output the file name where the logging request was
|
||||
issued.
|
||||
|
||||
<p><b>WARNING</b> Generating caller location information is
|
||||
extremely slow and should be avoided unless execution speed
|
||||
is not an issue.
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>l</b></td>
|
||||
|
||||
<td>Used to output location information of the caller which generated
|
||||
the logging event.
|
||||
|
||||
<p>The location information depends on the JVM implementation but
|
||||
usually consists of the fully qualified name of the calling
|
||||
method followed by the callers source the file name and line
|
||||
number between parentheses.
|
||||
|
||||
<p>The location information can be very useful. However, its
|
||||
generation is <em>extremely</em> slow and should be avoided
|
||||
unless execution speed is not an issue.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>L</b></td>
|
||||
|
||||
<td>Used to output the line number from where the logging request
|
||||
was issued.
|
||||
|
||||
<p><b>WARNING</b> Generating caller location information is
|
||||
extremely slow and should be avoided unless execution speed
|
||||
is not an issue.
|
||||
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td align=center><b>m</b></td>
|
||||
<td>Used to output the application supplied message associated with
|
||||
the logging event.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>M</b></td>
|
||||
|
||||
<td>Used to output the method name where the logging request was
|
||||
issued.
|
||||
|
||||
<p><b>WARNING</b> Generating caller location information is
|
||||
extremely slow and should be avoided unless execution speed
|
||||
is not an issue.
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>n</b></td>
|
||||
|
||||
<td>Outputs the platform dependent line separator character or
|
||||
characters.
|
||||
|
||||
<p>This conversion character offers practically the same
|
||||
performance as using non-portable line separator strings such as
|
||||
"\n", or "\r\n". Thus, it is the preferred way of specifying a
|
||||
line separator.
|
||||
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align=center><b>p</b></td>
|
||||
<td>Used to output the priority of the logging event.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td align=center><b>r</b></td>
|
||||
|
||||
<td>Used to output the number of milliseconds elapsed from the construction
|
||||
of the layout until the creation of the logging event.</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td align=center><b>t</b></td>
|
||||
|
||||
<td>Used to output the name of the thread that generated the
|
||||
logging event.</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td align=center><b>x</b></td>
|
||||
|
||||
<td>Used to output the NDC (nested diagnostic context) associated
|
||||
with the thread that generated the logging event.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<tr>
|
||||
<td align=center><b>X</b></td>
|
||||
|
||||
<td>
|
||||
|
||||
<p>Used to output the MDC (mapped diagnostic context) associated
|
||||
with the thread that generated the logging event. The <b>X</b>
|
||||
conversion character <em>must</em> be followed by the key for the
|
||||
map placed between braces, as in <b>%X{clientNumber}</b> where
|
||||
<code>clientNumber</code> is the key. The value in the MDC
|
||||
corresponding to the key will be output.</p>
|
||||
|
||||
<p>See {@link MDC} class for more details.
|
||||
</p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td align=center><b>%</b></td>
|
||||
|
||||
<td>The sequence %% outputs a single percent sign.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<p>By default the relevant information is output as is. However,
|
||||
with the aid of format modifiers it is possible to change the
|
||||
minimum field width, the maximum field width and justification.
|
||||
|
||||
<p>The optional format modifier is placed between the percent sign
|
||||
and the conversion character.
|
||||
|
||||
<p>The first optional format modifier is the <em>left justification
|
||||
flag</em> which is just the minus (-) character. Then comes the
|
||||
optional <em>minimum field width</em> modifier. This is a decimal
|
||||
constant that represents the minimum number of characters to
|
||||
output. If the data item requires fewer characters, it is padded on
|
||||
either the left or the right until the minimum width is
|
||||
reached. The default is to pad on the left (right justify) but you
|
||||
can specify right padding with the left justification flag. The
|
||||
padding character is space. If the data item is larger than the
|
||||
minimum field width, the field is expanded to accommodate the
|
||||
data. The value is never truncated.
|
||||
|
||||
<p>This behavior can be changed using the <em>maximum field
|
||||
width</em> modifier which is designated by a period followed by a
|
||||
decimal constant. If the data item is longer than the maximum
|
||||
field, then the extra characters are removed from the
|
||||
<em>beginning</em> of the data item and not from the end. For
|
||||
example, it the maximum field width is eight and the data item is
|
||||
ten characters long, then the first two characters of the data item
|
||||
are dropped. This behavior deviates from the printf function in C
|
||||
where truncation is done from the end.
|
||||
|
||||
<p>Below are various format modifier examples for the category
|
||||
conversion specifier.
|
||||
|
||||
<p>
|
||||
<TABLE BORDER=1 CELLPADDING=8>
|
||||
<th>Format modifier
|
||||
<th>left justify
|
||||
<th>minimum width
|
||||
<th>maximum width
|
||||
<th>comment
|
||||
|
||||
<tr>
|
||||
<td align=center>%20c</td>
|
||||
<td align=center>false</td>
|
||||
<td align=center>20</td>
|
||||
<td align=center>none</td>
|
||||
|
||||
<td>Left pad with spaces if the category name is less than 20
|
||||
characters long.
|
||||
|
||||
<tr> <td align=center>%-20c</td> <td align=center>true</td> <td
|
||||
align=center>20</td> <td align=center>none</td> <td>Right pad with
|
||||
spaces if the category name is less than 20 characters long.
|
||||
|
||||
<tr>
|
||||
<td align=center>%.30c</td>
|
||||
<td align=center>NA</td>
|
||||
<td align=center>none</td>
|
||||
<td align=center>30</td>
|
||||
|
||||
<td>Truncate from the beginning if the category name is longer than 30
|
||||
characters.
|
||||
|
||||
<tr>
|
||||
<td align=center>%20.30c</td>
|
||||
<td align=center>false</td>
|
||||
<td align=center>20</td>
|
||||
<td align=center>30</td>
|
||||
|
||||
<td>Left pad with spaces if the category name is shorter than 20
|
||||
characters. However, if category name is longer than 30 characters,
|
||||
then truncate from the beginning.
|
||||
|
||||
<tr>
|
||||
<td align=center>%-20.30c</td>
|
||||
<td align=center>true</td>
|
||||
<td align=center>20</td>
|
||||
<td align=center>30</td>
|
||||
|
||||
<td>Right pad with spaces if the category name is shorter than 20
|
||||
characters. However, if category name is longer than 30 characters,
|
||||
then truncate from the beginning.
|
||||
|
||||
</table>
|
||||
|
||||
<p>Below are some examples of conversion patterns.
|
||||
|
||||
<dl>
|
||||
|
||||
<p><dt><b>%r [%t] %-5p %c %x - %m%n</b>
|
||||
<p><dd>This is essentially the TTCC layout.
|
||||
|
||||
<p><dt><b>%-6r [%15.15t] %-5p %30.30c %x - %m%n</b>
|
||||
|
||||
<p><dd>Similar to the TTCC layout except that the relative time is
|
||||
right padded if less than 6 digits, thread name is right padded if
|
||||
less than 15 characters and truncated if longer and the category
|
||||
name is left padded if shorter than 30 characters and truncated if
|
||||
longer.
|
||||
|
||||
</dl>
|
||||
|
||||
<p>The above text is largely inspired from Peter A. Darnell and
|
||||
Philip E. Margolis' highly recommended book "C -- a Software
|
||||
Engineering Approach", ISBN 0-387-97389-3.
|
||||
|
||||
@author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
|
||||
@author Ceki Gülcü
|
||||
|
||||
|
||||
@since 0.8.2 */
|
||||
public class PatternLayout extends Layout {
|
||||
|
||||
|
||||
/** Default pattern string for log output. Currently set to the
|
||||
string <b>"%m%n"</b> which just prints the application supplied
|
||||
message. */
|
||||
public final static String DEFAULT_CONVERSION_PATTERN ="%m%n";
|
||||
|
||||
/** A conversion pattern equivalent to the TTCCCLayout.
|
||||
Current value is <b>%r [%t] %p %c %x - %m%n</b>. */
|
||||
public final static String TTCC_CONVERSION_PATTERN
|
||||
= "%r [%t] %p %c %x - %m%n";
|
||||
|
||||
|
||||
protected final int BUF_SIZE = 256;
|
||||
protected final int MAX_CAPACITY = 1024;
|
||||
|
||||
|
||||
// output buffer appended to when format() is invoked
|
||||
private StringBuffer sbuf = new StringBuffer(BUF_SIZE);
|
||||
|
||||
private String pattern;
|
||||
|
||||
private PatternConverter head;
|
||||
|
||||
/**
|
||||
Constructs a PatternLayout using the DEFAULT_LAYOUT_PATTERN.
|
||||
|
||||
The default pattern just produces the application supplied message.
|
||||
*/
|
||||
public PatternLayout() {
|
||||
this(DEFAULT_CONVERSION_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
Constructs a PatternLayout using the supplied conversion pattern.
|
||||
*/
|
||||
public PatternLayout(String pattern) {
|
||||
this.pattern = pattern;
|
||||
head = createPatternParser((pattern == null) ? DEFAULT_CONVERSION_PATTERN :
|
||||
pattern).parse();
|
||||
}
|
||||
|
||||
/**
|
||||
Set the <b>ConversionPattern</b> option. This is the string which
|
||||
controls formatting and consists of a mix of literal content and
|
||||
conversion specifiers.
|
||||
*/
|
||||
public
|
||||
void setConversionPattern(String conversionPattern) {
|
||||
pattern = conversionPattern;
|
||||
head = createPatternParser(conversionPattern).parse();
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the value of the <b>ConversionPattern</b> option.
|
||||
*/
|
||||
public
|
||||
String getConversionPattern() {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
Does not do anything as options become effective
|
||||
*/
|
||||
public
|
||||
void activateOptions() {
|
||||
// nothing to do.
|
||||
}
|
||||
|
||||
/**
|
||||
The PatternLayout does not handle the throwable contained within
|
||||
{@link LoggingEvent LoggingEvents}. Thus, it returns
|
||||
<code>true</code>.
|
||||
|
||||
@since 0.8.4 */
|
||||
public
|
||||
boolean ignoresThrowable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns PatternParser used to parse the conversion string. Subclasses
|
||||
may override this to return a subclass of PatternParser which recognize
|
||||
custom conversion characters.
|
||||
|
||||
@since 0.9.0
|
||||
*/
|
||||
protected PatternParser createPatternParser(String pattern) {
|
||||
return new PatternParser(pattern);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Produces a formatted string as specified by the conversion pattern.
|
||||
*/
|
||||
public String format(LoggingEvent event) {
|
||||
// Reset working stringbuffer
|
||||
if(sbuf.capacity() > MAX_CAPACITY) {
|
||||
sbuf = new StringBuffer(BUF_SIZE);
|
||||
} else {
|
||||
sbuf.setLength(0);
|
||||
}
|
||||
|
||||
PatternConverter c = head;
|
||||
|
||||
while(c != null) {
|
||||
c.format(sbuf, event);
|
||||
c = c.next;
|
||||
}
|
||||
return sbuf.toString();
|
||||
}
|
||||
}
|
||||
193
java/src/org/apache/log4j/Priority.java
Normal file
193
java/src/org/apache/log4j/Priority.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
// Contributors: Kitching Simon <Simon.Kitching@orange.ch>
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
/**
|
||||
<font color="#AA4444">Refrain from using this class directly, use
|
||||
the {@link Level} class instead</font>.
|
||||
|
||||
@author Ceki Gülcü */
|
||||
public class Priority {
|
||||
|
||||
transient int level;
|
||||
transient String levelStr;
|
||||
transient int syslogEquivalent;
|
||||
|
||||
public final static int OFF_INT = Integer.MAX_VALUE;
|
||||
public final static int FATAL_INT = 50000;
|
||||
public final static int ERROR_INT = 40000;
|
||||
public final static int WARN_INT = 30000;
|
||||
public final static int INFO_INT = 20000;
|
||||
public final static int DEBUG_INT = 10000;
|
||||
//public final static int FINE_INT = DEBUG_INT;
|
||||
public final static int ALL_INT = Integer.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Level#FATAL} instead.
|
||||
*/
|
||||
final static public Priority FATAL = new Level(FATAL_INT, "FATAL", 0);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Level#ERROR} instead.
|
||||
*/
|
||||
final static public Priority ERROR = new Level(ERROR_INT, "ERROR", 3);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Level#WARN} instead.
|
||||
*/
|
||||
final static public Priority WARN = new Level(WARN_INT, "WARN", 4);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Level#INFO} instead.
|
||||
*/
|
||||
final static public Priority INFO = new Level(INFO_INT, "INFO", 6);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link Level#DEBUG} instead.
|
||||
*/
|
||||
final static public Priority DEBUG = new Level(DEBUG_INT, "DEBUG", 7);
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor for deserialization.
|
||||
*/
|
||||
protected Priority() {
|
||||
level = DEBUG_INT;
|
||||
levelStr = "DEBUG";
|
||||
syslogEquivalent = 7;
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate a level object.
|
||||
*/
|
||||
protected
|
||||
Priority(int level, String levelStr, int syslogEquivalent) {
|
||||
this.level = level;
|
||||
this.levelStr = levelStr;
|
||||
this.syslogEquivalent = syslogEquivalent;
|
||||
}
|
||||
|
||||
/**
|
||||
Two priorities are equal if their level fields are equal.
|
||||
@since 1.2
|
||||
*/
|
||||
public
|
||||
boolean equals(Object o) {
|
||||
if(o instanceof Priority) {
|
||||
Priority r = (Priority) o;
|
||||
return (this.level == r.level);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Return the syslog equivalent of this priority as an integer.
|
||||
*/
|
||||
public
|
||||
final
|
||||
int getSyslogEquivalent() {
|
||||
return syslogEquivalent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Returns <code>true</code> if this level has a higher or equal
|
||||
level than the level passed as argument, <code>false</code>
|
||||
otherwise.
|
||||
|
||||
<p>You should think twice before overriding the default
|
||||
implementation of <code>isGreaterOrEqual</code> method.
|
||||
|
||||
*/
|
||||
public
|
||||
boolean isGreaterOrEqual(Priority r) {
|
||||
return level >= r.level;
|
||||
}
|
||||
|
||||
/**
|
||||
Return all possible priorities as an array of Level objects in
|
||||
descending order.
|
||||
|
||||
@deprecated This method will be removed with no replacement.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Priority[] getAllPossiblePriorities() {
|
||||
return new Priority[] {Priority.FATAL, Priority.ERROR, Level.WARN,
|
||||
Priority.INFO, Priority.DEBUG};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns the string representation of this priority.
|
||||
*/
|
||||
final
|
||||
public
|
||||
String toString() {
|
||||
return levelStr;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the integer representation of this level.
|
||||
*/
|
||||
public
|
||||
final
|
||||
int toInt() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Please use the {@link Level#toLevel(String)} method instead.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Priority toPriority(String sArg) {
|
||||
return Level.toLevel(sArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Please use the {@link Level#toLevel(int)} method instead.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Priority toPriority(int val) {
|
||||
return toPriority(val, Priority.DEBUG);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Please use the {@link Level#toLevel(int, Level)} method instead.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Priority toPriority(int val, Priority defaultPriority) {
|
||||
return Level.toLevel(val, (Level) defaultPriority);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Please use the {@link Level#toLevel(String, Level)} method instead.
|
||||
*/
|
||||
public
|
||||
static
|
||||
Priority toPriority(String sArg, Priority defaultPriority) {
|
||||
return Level.toLevel(sArg, (Level) defaultPriority);
|
||||
}
|
||||
}
|
||||
963
java/src/org/apache/log4j/PropertyConfigurator.java
Normal file
963
java/src/org/apache/log4j/PropertyConfigurator.java
Normal file
@@ -0,0 +1,963 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
|
||||
// Contibutors: "Luke Blanshard" <Luke@quiq.com>
|
||||
// "Mark DONSZELMANN" <Mark.Donszelmann@cern.ch>
|
||||
// Anders Kristensen <akristensen@dynamicsoft.com>
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.log4j.config.PropertySetter;
|
||||
import org.apache.log4j.helpers.FileWatchdog;
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
import org.apache.log4j.helpers.OptionConverter;
|
||||
import org.apache.log4j.or.RendererMap;
|
||||
import org.apache.log4j.spi.Configurator;
|
||||
import org.apache.log4j.spi.Filter;
|
||||
import org.apache.log4j.spi.LoggerFactory;
|
||||
import org.apache.log4j.spi.LoggerRepository;
|
||||
import org.apache.log4j.spi.OptionHandler;
|
||||
import org.apache.log4j.spi.RendererSupport;
|
||||
import org.apache.log4j.spi.ThrowableRenderer;
|
||||
import org.apache.log4j.spi.ThrowableRendererSupport;
|
||||
import org.apache.log4j.spi.ErrorHandler;
|
||||
|
||||
/**
|
||||
Allows the configuration of log4j from an external file. See
|
||||
<b>{@link #doConfigure(String, LoggerRepository)}</b> for the
|
||||
expected format.
|
||||
|
||||
<p>It is sometimes useful to see how log4j is reading configuration
|
||||
files. You can enable log4j internal logging by defining the
|
||||
<b>log4j.debug</b> variable.
|
||||
|
||||
<P>As of log4j version 0.8.5, at class initialization time class,
|
||||
the file <b>log4j.properties</b> will be searched from the search
|
||||
path used to load classes. If the file can be found, then it will
|
||||
be fed to the {@link PropertyConfigurator#configure(java.net.URL)}
|
||||
method.
|
||||
|
||||
<p>The <code>PropertyConfigurator</code> does not handle the
|
||||
advanced configuration features supported by the {@link
|
||||
org.apache.log4j.xml.DOMConfigurator DOMConfigurator} such as
|
||||
support custom {@link org.apache.log4j.spi.ErrorHandler ErrorHandlers},
|
||||
nested appenders such as the {@link org.apache.log4j.AsyncAppender
|
||||
AsyncAppender}, etc.
|
||||
|
||||
<p>All option <em>values</em> admit variable substitution. The
|
||||
syntax of variable substitution is similar to that of Unix
|
||||
shells. The string between an opening <b>"${"</b> and
|
||||
closing <b>"}"</b> is interpreted as a key. The value of
|
||||
the substituted variable can be defined as a system property or in
|
||||
the configuration file itself. The value of the key is first
|
||||
searched in the system properties, and if not found there, it is
|
||||
then searched in the configuration file being parsed. The
|
||||
corresponding value replaces the ${variableName} sequence. For
|
||||
example, if <code>java.home</code> system property is set to
|
||||
<code>/home/xyz</code>, then every occurrence of the sequence
|
||||
<code>${java.home}</code> will be interpreted as
|
||||
<code>/home/xyz</code>.
|
||||
|
||||
|
||||
@author Ceki Gülcü
|
||||
@author Anders Kristensen
|
||||
@since 0.8.1 */
|
||||
public class PropertyConfigurator implements Configurator {
|
||||
|
||||
/**
|
||||
Used internally to keep track of configured appenders.
|
||||
*/
|
||||
protected Hashtable registry = new Hashtable(11);
|
||||
private LoggerRepository repository;
|
||||
protected LoggerFactory loggerFactory = new DefaultCategoryFactory();
|
||||
|
||||
static final String CATEGORY_PREFIX = "log4j.category.";
|
||||
static final String LOGGER_PREFIX = "log4j.logger.";
|
||||
static final String FACTORY_PREFIX = "log4j.factory";
|
||||
static final String ADDITIVITY_PREFIX = "log4j.additivity.";
|
||||
static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
|
||||
static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger";
|
||||
static final String APPENDER_PREFIX = "log4j.appender.";
|
||||
static final String RENDERER_PREFIX = "log4j.renderer.";
|
||||
static final String THRESHOLD_PREFIX = "log4j.threshold";
|
||||
private static final String THROWABLE_RENDERER_PREFIX = "log4j.throwableRenderer";
|
||||
private static final String LOGGER_REF = "logger-ref";
|
||||
private static final String ROOT_REF = "root-ref";
|
||||
private static final String APPENDER_REF_TAG = "appender-ref";
|
||||
|
||||
|
||||
/** Key for specifying the {@link org.apache.log4j.spi.LoggerFactory
|
||||
LoggerFactory}. Currently set to "<code>log4j.loggerFactory</code>". */
|
||||
public static final String LOGGER_FACTORY_KEY = "log4j.loggerFactory";
|
||||
|
||||
/**
|
||||
* If property set to true, then hierarchy will be reset before configuration.
|
||||
*/
|
||||
private static final String RESET_KEY = "log4j.reset";
|
||||
|
||||
static final private String INTERNAL_ROOT_NAME = "root";
|
||||
|
||||
/**
|
||||
Read configuration from a file. <b>The existing configuration is
|
||||
not cleared nor reset.</b> If you require a different behavior,
|
||||
then call {@link LogManager#resetConfiguration
|
||||
resetConfiguration} method before calling
|
||||
<code>doConfigure</code>.
|
||||
|
||||
<p>The configuration file consists of statements in the format
|
||||
<code>key=value</code>. The syntax of different configuration
|
||||
elements are discussed below.
|
||||
|
||||
<h3>Repository-wide threshold</h3>
|
||||
|
||||
<p>The repository-wide threshold filters logging requests by level
|
||||
regardless of logger. The syntax is:
|
||||
|
||||
<pre>
|
||||
log4j.threshold=[level]
|
||||
</pre>
|
||||
|
||||
<p>The level value can consist of the string values OFF, FATAL,
|
||||
ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
|
||||
custom level value can be specified in the form
|
||||
level#classname. By default the repository-wide threshold is set
|
||||
to the lowest possible value, namely the level <code>ALL</code>.
|
||||
</p>
|
||||
|
||||
|
||||
<h3>Appender configuration</h3>
|
||||
|
||||
<p>Appender configuration syntax is:
|
||||
<pre>
|
||||
# For appender named <i>appenderName</i>, set its class.
|
||||
# Note: The appender name can contain dots.
|
||||
log4j.appender.appenderName=fully.qualified.name.of.appender.class
|
||||
|
||||
# Set appender specific options.
|
||||
log4j.appender.appenderName.option1=value1
|
||||
...
|
||||
log4j.appender.appenderName.optionN=valueN
|
||||
</pre>
|
||||
|
||||
For each named appender you can configure its {@link Layout}. The
|
||||
syntax for configuring an appender's layout is:
|
||||
<pre>
|
||||
log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class
|
||||
log4j.appender.appenderName.layout.option1=value1
|
||||
....
|
||||
log4j.appender.appenderName.layout.optionN=valueN
|
||||
</pre>
|
||||
|
||||
The syntax for adding {@link Filter}s to an appender is:
|
||||
<pre>
|
||||
log4j.appender.appenderName.filter.ID=fully.qualified.name.of.filter.class
|
||||
log4j.appender.appenderName.filter.ID.option1=value1
|
||||
...
|
||||
log4j.appender.appenderName.filter.ID.optionN=valueN
|
||||
</pre>
|
||||
The first line defines the class name of the filter identified by ID;
|
||||
subsequent lines with the same ID specify filter option - value
|
||||
paris. Multiple filters are added to the appender in the lexicographic
|
||||
order of IDs.
|
||||
|
||||
The syntax for adding an {@link ErrorHandler} to an appender is:
|
||||
<pre>
|
||||
log4j.appender.appenderName.errorhandler=fully.qualified.name.of.filter.class
|
||||
log4j.appender.appenderName.errorhandler.root-ref={true|false}
|
||||
log4j.appender.appenderName.errorhandler.logger-ref=loggerName
|
||||
log4j.appender.appenderName.errorhandler.appender-ref=appenderName
|
||||
log4j.appender.appenderName.errorhandler.option1=value1
|
||||
...
|
||||
log4j.appender.appenderName.errorhandler.optionN=valueN
|
||||
</pre>
|
||||
|
||||
<h3>Configuring loggers</h3>
|
||||
|
||||
<p>The syntax for configuring the root logger is:
|
||||
<pre>
|
||||
log4j.rootLogger=[level], appenderName, appenderName, ...
|
||||
</pre>
|
||||
|
||||
<p>This syntax means that an optional <em>level</em> can be
|
||||
supplied followed by appender names separated by commas.
|
||||
|
||||
<p>The level value can consist of the string values OFF, FATAL,
|
||||
ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
|
||||
custom level value can be specified in the form
|
||||
<code>level#classname</code>.
|
||||
|
||||
<p>If a level value is specified, then the root level is set
|
||||
to the corresponding level. If no level value is specified,
|
||||
then the root level remains untouched.
|
||||
|
||||
<p>The root logger can be assigned multiple appenders.
|
||||
|
||||
<p>Each <i>appenderName</i> (separated by commas) will be added to
|
||||
the root logger. The named appender is defined using the
|
||||
appender syntax defined above.
|
||||
|
||||
<p>For non-root categories the syntax is almost the same:
|
||||
<pre>
|
||||
log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...
|
||||
</pre>
|
||||
|
||||
<p>The meaning of the optional level value is discussed above
|
||||
in relation to the root logger. In addition however, the value
|
||||
INHERITED can be specified meaning that the named logger should
|
||||
inherit its level from the logger hierarchy.
|
||||
|
||||
<p>If no level value is supplied, then the level of the
|
||||
named logger remains untouched.
|
||||
|
||||
<p>By default categories inherit their level from the
|
||||
hierarchy. However, if you set the level of a logger and later
|
||||
decide that that logger should inherit its level, then you should
|
||||
specify INHERITED as the value for the level value. NULL is a
|
||||
synonym for INHERITED.
|
||||
|
||||
<p>Similar to the root logger syntax, each <i>appenderName</i>
|
||||
(separated by commas) will be attached to the named logger.
|
||||
|
||||
<p>See the <a href="../../../../manual.html#additivity">appender
|
||||
additivity rule</a> in the user manual for the meaning of the
|
||||
<code>additivity</code> flag.
|
||||
|
||||
<h3>ObjectRenderers</h3>
|
||||
|
||||
You can customize the way message objects of a given type are
|
||||
converted to String before being logged. This is done by
|
||||
specifying an {@link org.apache.log4j.or.ObjectRenderer ObjectRenderer}
|
||||
for the object type would like to customize.
|
||||
|
||||
<p>The syntax is:
|
||||
|
||||
<pre>
|
||||
log4j.renderer.fully.qualified.name.of.rendered.class=fully.qualified.name.of.rendering.class
|
||||
</pre>
|
||||
|
||||
As in,
|
||||
<pre>
|
||||
log4j.renderer.my.Fruit=my.FruitRenderer
|
||||
</pre>
|
||||
|
||||
<h3>ThrowableRenderer</h3>
|
||||
|
||||
You can customize the way an instance of Throwable is
|
||||
converted to String before being logged. This is done by
|
||||
specifying an {@link org.apache.log4j.spi.ThrowableRenderer ThrowableRenderer}.
|
||||
|
||||
<p>The syntax is:
|
||||
|
||||
<pre>
|
||||
log4j.throwableRenderer=fully.qualified.name.of.rendering.class
|
||||
log4j.throwableRenderer.paramName=paramValue
|
||||
</pre>
|
||||
|
||||
As in,
|
||||
<pre>
|
||||
log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
|
||||
</pre>
|
||||
|
||||
<h3>Logger Factories</h3>
|
||||
|
||||
The usage of custom logger factories is discouraged and no longer
|
||||
documented.
|
||||
|
||||
<h3>Resetting Hierarchy</h3>
|
||||
|
||||
The hierarchy will be reset before configuration when
|
||||
log4j.reset=true is present in the properties file.
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
<p>An example configuration is given below. Other configuration
|
||||
file examples are given in the <code>examples</code> folder.
|
||||
|
||||
<pre>
|
||||
|
||||
# Set options for appender named "A1".
|
||||
# Appender "A1" will be a SyslogAppender
|
||||
log4j.appender.A1=org.apache.log4j.net.SyslogAppender
|
||||
|
||||
# The syslog daemon resides on www.abc.net
|
||||
log4j.appender.A1.SyslogHost=www.abc.net
|
||||
|
||||
# A1's layout is a PatternLayout, using the conversion pattern
|
||||
# <b>%r %-5p %c{2} %M.%L %x - %m\n</b>. Thus, the log output will
|
||||
# include # the relative time since the start of the application in
|
||||
# milliseconds, followed by the level of the log request,
|
||||
# followed by the two rightmost components of the logger name,
|
||||
# followed by the callers method name, followed by the line number,
|
||||
# the nested disgnostic context and finally the message itself.
|
||||
# Refer to the documentation of {@link PatternLayout} for further information
|
||||
# on the syntax of the ConversionPattern key.
|
||||
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c{2} %M.%L %x - %m\n
|
||||
|
||||
# Set options for appender named "A2"
|
||||
# A2 should be a RollingFileAppender, with maximum file size of 10 MB
|
||||
# using at most one backup file. A2's layout is TTCC, using the
|
||||
# ISO8061 date format with context printing enabled.
|
||||
log4j.appender.A2=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.A2.MaxFileSize=10MB
|
||||
log4j.appender.A2.MaxBackupIndex=1
|
||||
log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
|
||||
log4j.appender.A2.layout.ContextPrinting=enabled
|
||||
log4j.appender.A2.layout.DateFormat=ISO8601
|
||||
|
||||
# Root logger set to DEBUG using the A2 appender defined above.
|
||||
log4j.rootLogger=DEBUG, A2
|
||||
|
||||
# Logger definitions:
|
||||
# The SECURITY logger inherits is level from root. However, it's output
|
||||
# will go to A1 appender defined above. It's additivity is non-cumulative.
|
||||
log4j.logger.SECURITY=INHERIT, A1
|
||||
log4j.additivity.SECURITY=false
|
||||
|
||||
# Only warnings or above will be logged for the logger "SECURITY.access".
|
||||
# Output will go to A1.
|
||||
log4j.logger.SECURITY.access=WARN
|
||||
|
||||
|
||||
# The logger "class.of.the.day" inherits its level from the
|
||||
# logger hierarchy. Output will go to the appender's of the root
|
||||
# logger, A2 in this case.
|
||||
log4j.logger.class.of.the.day=INHERIT
|
||||
</pre>
|
||||
|
||||
<p>Refer to the <b>setOption</b> method in each Appender and
|
||||
Layout for class specific options.
|
||||
|
||||
<p>Use the <code>#</code> or <code>!</code> characters at the
|
||||
beginning of a line for comments.
|
||||
|
||||
<p>
|
||||
@param configFileName The name of the configuration file where the
|
||||
configuration information is stored.
|
||||
|
||||
*/
|
||||
public
|
||||
void doConfigure(String configFileName, LoggerRepository hierarchy) {
|
||||
Properties props = new Properties();
|
||||
FileInputStream istream = null;
|
||||
try {
|
||||
istream = new FileInputStream(configFileName);
|
||||
props.load(istream);
|
||||
istream.close();
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
LogLog.error("Could not read configuration file ["+configFileName+"].", e);
|
||||
LogLog.error("Ignoring configuration file [" + configFileName+"].");
|
||||
return;
|
||||
} finally {
|
||||
if(istream != null) {
|
||||
try {
|
||||
istream.close();
|
||||
} catch(InterruptedIOException ignore) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch(Throwable ignore) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// If we reach here, then the config file is alright.
|
||||
doConfigure(props, hierarchy);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
static
|
||||
public
|
||||
void configure(String configFilename) {
|
||||
new PropertyConfigurator().doConfigure(configFilename,
|
||||
LogManager.getLoggerRepository());
|
||||
}
|
||||
|
||||
/**
|
||||
Read configuration options from url <code>configURL</code>.
|
||||
|
||||
@since 0.8.2
|
||||
*/
|
||||
public
|
||||
static
|
||||
void configure(java.net.URL configURL) {
|
||||
new PropertyConfigurator().doConfigure(configURL,
|
||||
LogManager.getLoggerRepository());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Read configuration options from <code>properties</code>.
|
||||
|
||||
See {@link #doConfigure(String, LoggerRepository)} for the expected format.
|
||||
*/
|
||||
static
|
||||
public
|
||||
void configure(Properties properties) {
|
||||
new PropertyConfigurator().doConfigure(properties,
|
||||
LogManager.getLoggerRepository());
|
||||
}
|
||||
|
||||
/**
|
||||
Like {@link #configureAndWatch(String, long)} except that the
|
||||
default delay as defined by {@link FileWatchdog#DEFAULT_DELAY} is
|
||||
used.
|
||||
|
||||
@param configFilename A file in key=value format.
|
||||
|
||||
*/
|
||||
static
|
||||
public
|
||||
void configureAndWatch(String configFilename) {
|
||||
configureAndWatch(configFilename, FileWatchdog.DEFAULT_DELAY);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Read the configuration file <code>configFilename</code> if it
|
||||
exists. Moreover, a thread will be created that will periodically
|
||||
check if <code>configFilename</code> has been created or
|
||||
modified. The period is determined by the <code>delay</code>
|
||||
argument. If a change or file creation is detected, then
|
||||
<code>configFilename</code> is read to configure log4j.
|
||||
|
||||
@param configFilename A file in key=value format.
|
||||
@param delay The delay in milliseconds to wait between each check.
|
||||
*/
|
||||
static
|
||||
public
|
||||
void configureAndWatch(String configFilename, long delay) {
|
||||
PropertyWatchdog pdog = new PropertyWatchdog(configFilename);
|
||||
pdog.setDelay(delay);
|
||||
pdog.start();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Read configuration options from <code>properties</code>.
|
||||
|
||||
See {@link #doConfigure(String, LoggerRepository)} for the expected format.
|
||||
*/
|
||||
public
|
||||
void doConfigure(Properties properties, LoggerRepository hierarchy) {
|
||||
repository = hierarchy;
|
||||
String value = properties.getProperty(LogLog.DEBUG_KEY);
|
||||
if(value == null) {
|
||||
value = properties.getProperty("log4j.configDebug");
|
||||
if(value != null)
|
||||
LogLog.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
|
||||
}
|
||||
|
||||
if(value != null) {
|
||||
LogLog.setInternalDebugging(OptionConverter.toBoolean(value, true));
|
||||
}
|
||||
|
||||
//
|
||||
// if log4j.reset=true then
|
||||
// reset hierarchy
|
||||
String reset = properties.getProperty(RESET_KEY);
|
||||
if (reset != null && OptionConverter.toBoolean(reset, false)) {
|
||||
hierarchy.resetConfiguration();
|
||||
}
|
||||
|
||||
String thresholdStr = OptionConverter.findAndSubst(THRESHOLD_PREFIX,
|
||||
properties);
|
||||
if(thresholdStr != null) {
|
||||
hierarchy.setThreshold(OptionConverter.toLevel(thresholdStr,
|
||||
(Level) Level.ALL));
|
||||
LogLog.debug("Hierarchy threshold set to ["+hierarchy.getThreshold()+"].");
|
||||
}
|
||||
|
||||
configureRootCategory(properties, hierarchy);
|
||||
configureLoggerFactory(properties);
|
||||
parseCatsAndRenderers(properties, hierarchy);
|
||||
|
||||
LogLog.debug("Finished configuring.");
|
||||
// We don't want to hold references to appenders preventing their
|
||||
// garbage collection.
|
||||
registry.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
Read configuration options from url <code>configURL</code>.
|
||||
*/
|
||||
public
|
||||
void doConfigure(java.net.URL configURL, LoggerRepository hierarchy) {
|
||||
Properties props = new Properties();
|
||||
LogLog.debug("Reading configuration from URL " + configURL);
|
||||
InputStream istream = null;
|
||||
URLConnection uConn = null;
|
||||
try {
|
||||
uConn = configURL.openConnection();
|
||||
uConn.setUseCaches(false);
|
||||
istream = uConn.getInputStream();
|
||||
props.load(istream);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
LogLog.error("Could not read configuration file from URL [" + configURL
|
||||
+ "].", e);
|
||||
LogLog.error("Ignoring configuration file [" + configURL +"].");
|
||||
return;
|
||||
}
|
||||
finally {
|
||||
if (istream != null) {
|
||||
try {
|
||||
istream.close();
|
||||
} catch(InterruptedIOException ignore) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch(IOException ignore) {
|
||||
} catch(RuntimeException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
doConfigure(props, hierarchy);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Internal stuff
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
Check the provided <code>Properties</code> object for a
|
||||
{@link org.apache.log4j.spi.LoggerFactory LoggerFactory}
|
||||
entry specified by {@link #LOGGER_FACTORY_KEY}. If such an entry
|
||||
exists, an attempt is made to create an instance using the default
|
||||
constructor. This instance is used for subsequent Category creations
|
||||
within this configurator.
|
||||
|
||||
@see #parseCatsAndRenderers
|
||||
*/
|
||||
protected void configureLoggerFactory(Properties props) {
|
||||
String factoryClassName = OptionConverter.findAndSubst(LOGGER_FACTORY_KEY,
|
||||
props);
|
||||
if(factoryClassName != null) {
|
||||
LogLog.debug("Setting category factory to ["+factoryClassName+"].");
|
||||
loggerFactory = (LoggerFactory)
|
||||
OptionConverter.instantiateByClassName(factoryClassName,
|
||||
LoggerFactory.class,
|
||||
loggerFactory);
|
||||
PropertySetter.setProperties(loggerFactory, props, FACTORY_PREFIX + ".");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void configureOptionHandler(OptionHandler oh, String prefix,
|
||||
Properties props) {
|
||||
String[] options = oh.getOptionStrings();
|
||||
if(options == null)
|
||||
return;
|
||||
|
||||
String value;
|
||||
for(int i = 0; i < options.length; i++) {
|
||||
value = OptionConverter.findAndSubst(prefix + options[i], props);
|
||||
LogLog.debug(
|
||||
"Option " + options[i] + "=[" + (value == null? "N/A" : value)+"].");
|
||||
// Some option handlers assume that null value are not passed to them.
|
||||
// So don't remove this check
|
||||
if(value != null) {
|
||||
oh.setOption(options[i], value);
|
||||
}
|
||||
}
|
||||
oh.activateOptions();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void configureRootCategory(Properties props, LoggerRepository hierarchy) {
|
||||
String effectiveFrefix = ROOT_LOGGER_PREFIX;
|
||||
String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);
|
||||
|
||||
if(value == null) {
|
||||
value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
|
||||
effectiveFrefix = ROOT_CATEGORY_PREFIX;
|
||||
}
|
||||
|
||||
if(value == null)
|
||||
LogLog.debug("Could not find root logger information. Is this OK?");
|
||||
else {
|
||||
Logger root = hierarchy.getRootLogger();
|
||||
synchronized(root) {
|
||||
parseCategory(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Parse non-root elements, such non-root categories and renderers.
|
||||
*/
|
||||
protected
|
||||
void parseCatsAndRenderers(Properties props, LoggerRepository hierarchy) {
|
||||
Enumeration enumeration = props.propertyNames();
|
||||
while(enumeration.hasMoreElements()) {
|
||||
String key = (String) enumeration.nextElement();
|
||||
if(key.startsWith(CATEGORY_PREFIX) || key.startsWith(LOGGER_PREFIX)) {
|
||||
String loggerName = null;
|
||||
if(key.startsWith(CATEGORY_PREFIX)) {
|
||||
loggerName = key.substring(CATEGORY_PREFIX.length());
|
||||
} else if(key.startsWith(LOGGER_PREFIX)) {
|
||||
loggerName = key.substring(LOGGER_PREFIX.length());
|
||||
}
|
||||
String value = OptionConverter.findAndSubst(key, props);
|
||||
Logger logger = hierarchy.getLogger(loggerName, loggerFactory);
|
||||
synchronized(logger) {
|
||||
parseCategory(props, logger, key, loggerName, value);
|
||||
parseAdditivityForLogger(props, logger, loggerName);
|
||||
}
|
||||
} else if(key.startsWith(RENDERER_PREFIX)) {
|
||||
String renderedClass = key.substring(RENDERER_PREFIX.length());
|
||||
String renderingClass = OptionConverter.findAndSubst(key, props);
|
||||
if(hierarchy instanceof RendererSupport) {
|
||||
RendererMap.addRenderer((RendererSupport) hierarchy, renderedClass,
|
||||
renderingClass);
|
||||
}
|
||||
} else if (key.equals(THROWABLE_RENDERER_PREFIX)) {
|
||||
if (hierarchy instanceof ThrowableRendererSupport) {
|
||||
ThrowableRenderer tr = (ThrowableRenderer)
|
||||
OptionConverter.instantiateByKey(props,
|
||||
THROWABLE_RENDERER_PREFIX,
|
||||
org.apache.log4j.spi.ThrowableRenderer.class,
|
||||
null);
|
||||
if(tr == null) {
|
||||
LogLog.error(
|
||||
"Could not instantiate throwableRenderer.");
|
||||
} else {
|
||||
PropertySetter setter = new PropertySetter(tr);
|
||||
setter.setProperties(props, THROWABLE_RENDERER_PREFIX + ".");
|
||||
((ThrowableRendererSupport) hierarchy).setThrowableRenderer(tr);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Parse the additivity option for a non-root category.
|
||||
*/
|
||||
void parseAdditivityForLogger(Properties props, Logger cat,
|
||||
String loggerName) {
|
||||
String value = OptionConverter.findAndSubst(ADDITIVITY_PREFIX + loggerName,
|
||||
props);
|
||||
LogLog.debug("Handling "+ADDITIVITY_PREFIX + loggerName+"=["+value+"]");
|
||||
// touch additivity only if necessary
|
||||
if((value != null) && (!value.equals(""))) {
|
||||
boolean additivity = OptionConverter.toBoolean(value, true);
|
||||
LogLog.debug("Setting additivity for \""+loggerName+"\" to "+
|
||||
additivity);
|
||||
cat.setAdditivity(additivity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
This method must work for the root category as well.
|
||||
*/
|
||||
void parseCategory(Properties props, Logger logger, String optionKey,
|
||||
String loggerName, String value) {
|
||||
|
||||
LogLog.debug("Parsing for [" +loggerName +"] with value=[" + value+"].");
|
||||
// We must skip over ',' but not white space
|
||||
StringTokenizer st = new StringTokenizer(value, ",");
|
||||
|
||||
// If value is not in the form ", appender.." or "", then we should set
|
||||
// the level of the loggeregory.
|
||||
|
||||
if(!(value.startsWith(",") || value.equals(""))) {
|
||||
|
||||
// just to be on the safe side...
|
||||
if(!st.hasMoreTokens())
|
||||
return;
|
||||
|
||||
String levelStr = st.nextToken();
|
||||
LogLog.debug("Level token is [" + levelStr + "].");
|
||||
|
||||
// If the level value is inherited, set category level value to
|
||||
// null. We also check that the user has not specified inherited for the
|
||||
// root category.
|
||||
if(INHERITED.equalsIgnoreCase(levelStr) ||
|
||||
NULL.equalsIgnoreCase(levelStr)) {
|
||||
if(loggerName.equals(INTERNAL_ROOT_NAME)) {
|
||||
LogLog.warn("The root logger cannot be set to null.");
|
||||
} else {
|
||||
logger.setLevel(null);
|
||||
}
|
||||
} else {
|
||||
logger.setLevel(OptionConverter.toLevel(levelStr, (Level) Level.DEBUG));
|
||||
}
|
||||
LogLog.debug("Category " + loggerName + " set to " + logger.getLevel());
|
||||
}
|
||||
|
||||
// Begin by removing all existing appenders.
|
||||
logger.removeAllAppenders();
|
||||
|
||||
Appender appender;
|
||||
String appenderName;
|
||||
while(st.hasMoreTokens()) {
|
||||
appenderName = st.nextToken().trim();
|
||||
if(appenderName == null || appenderName.equals(","))
|
||||
continue;
|
||||
LogLog.debug("Parsing appender named \"" + appenderName +"\".");
|
||||
appender = parseAppender(props, appenderName);
|
||||
if(appender != null) {
|
||||
logger.addAppender(appender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Appender parseAppender(Properties props, String appenderName) {
|
||||
Appender appender = registryGet(appenderName);
|
||||
if((appender != null)) {
|
||||
LogLog.debug("Appender \"" + appenderName + "\" was already parsed.");
|
||||
return appender;
|
||||
}
|
||||
// Appender was not previously initialized.
|
||||
String prefix = APPENDER_PREFIX + appenderName;
|
||||
String layoutPrefix = prefix + ".layout";
|
||||
|
||||
appender = (Appender) OptionConverter.instantiateByKey(props, prefix,
|
||||
org.apache.log4j.Appender.class,
|
||||
null);
|
||||
if(appender == null) {
|
||||
LogLog.error(
|
||||
"Could not instantiate appender named \"" + appenderName+"\".");
|
||||
return null;
|
||||
}
|
||||
appender.setName(appenderName);
|
||||
|
||||
if(appender instanceof OptionHandler) {
|
||||
if(appender.requiresLayout()) {
|
||||
Layout layout = (Layout) OptionConverter.instantiateByKey(props,
|
||||
layoutPrefix,
|
||||
Layout.class,
|
||||
null);
|
||||
if(layout != null) {
|
||||
appender.setLayout(layout);
|
||||
LogLog.debug("Parsing layout options for \"" + appenderName +"\".");
|
||||
//configureOptionHandler(layout, layoutPrefix + ".", props);
|
||||
PropertySetter.setProperties(layout, props, layoutPrefix + ".");
|
||||
LogLog.debug("End of parsing for \"" + appenderName +"\".");
|
||||
}
|
||||
}
|
||||
final String errorHandlerPrefix = prefix + ".errorhandler";
|
||||
String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props);
|
||||
if (errorHandlerClass != null) {
|
||||
ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByKey(props,
|
||||
errorHandlerPrefix,
|
||||
ErrorHandler.class,
|
||||
null);
|
||||
if (eh != null) {
|
||||
appender.setErrorHandler(eh);
|
||||
LogLog.debug("Parsing errorhandler options for \"" + appenderName +"\".");
|
||||
parseErrorHandler(eh, errorHandlerPrefix, props, repository);
|
||||
final Properties edited = new Properties();
|
||||
final String[] keys = new String[] {
|
||||
errorHandlerPrefix + "." + ROOT_REF,
|
||||
errorHandlerPrefix + "." + LOGGER_REF,
|
||||
errorHandlerPrefix + "." + APPENDER_REF_TAG
|
||||
};
|
||||
for(Iterator iter = props.entrySet().iterator();iter.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) iter.next();
|
||||
int i = 0;
|
||||
for(; i < keys.length; i++) {
|
||||
if(keys[i].equals(entry.getKey())) break;
|
||||
}
|
||||
if (i == keys.length) {
|
||||
edited.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
PropertySetter.setProperties(eh, edited, errorHandlerPrefix + ".");
|
||||
LogLog.debug("End of errorhandler parsing for \"" + appenderName +"\".");
|
||||
}
|
||||
|
||||
}
|
||||
//configureOptionHandler((OptionHandler) appender, prefix + ".", props);
|
||||
PropertySetter.setProperties(appender, props, prefix + ".");
|
||||
LogLog.debug("Parsed \"" + appenderName +"\" options.");
|
||||
}
|
||||
parseAppenderFilters(props, appenderName, appender);
|
||||
registryPut(appender);
|
||||
return appender;
|
||||
}
|
||||
|
||||
private void parseErrorHandler(
|
||||
final ErrorHandler eh,
|
||||
final String errorHandlerPrefix,
|
||||
final Properties props,
|
||||
final LoggerRepository hierarchy) {
|
||||
boolean rootRef = OptionConverter.toBoolean(
|
||||
OptionConverter.findAndSubst(errorHandlerPrefix + ROOT_REF, props), false);
|
||||
if (rootRef) {
|
||||
eh.setLogger(hierarchy.getRootLogger());
|
||||
}
|
||||
String loggerName = OptionConverter.findAndSubst(errorHandlerPrefix + LOGGER_REF , props);
|
||||
if (loggerName != null) {
|
||||
Logger logger = (loggerFactory == null) ? hierarchy.getLogger(loggerName)
|
||||
: hierarchy.getLogger(loggerName, loggerFactory);
|
||||
eh.setLogger(logger);
|
||||
}
|
||||
String appenderName = OptionConverter.findAndSubst(errorHandlerPrefix + APPENDER_REF_TAG, props);
|
||||
if (appenderName != null) {
|
||||
Appender backup = parseAppender(props, appenderName);
|
||||
if (backup != null) {
|
||||
eh.setBackupAppender(backup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void parseAppenderFilters(Properties props, String appenderName, Appender appender) {
|
||||
// extract filters and filter options from props into a hashtable mapping
|
||||
// the property name defining the filter class to a list of pre-parsed
|
||||
// name-value pairs associated to that filter
|
||||
final String filterPrefix = APPENDER_PREFIX + appenderName + ".filter.";
|
||||
int fIdx = filterPrefix.length();
|
||||
Hashtable filters = new Hashtable();
|
||||
Enumeration e = props.keys();
|
||||
String name = "";
|
||||
while (e.hasMoreElements()) {
|
||||
String key = (String) e.nextElement();
|
||||
if (key.startsWith(filterPrefix)) {
|
||||
int dotIdx = key.indexOf('.', fIdx);
|
||||
String filterKey = key;
|
||||
if (dotIdx != -1) {
|
||||
filterKey = key.substring(0, dotIdx);
|
||||
name = key.substring(dotIdx+1);
|
||||
}
|
||||
Vector filterOpts = (Vector) filters.get(filterKey);
|
||||
if (filterOpts == null) {
|
||||
filterOpts = new Vector();
|
||||
filters.put(filterKey, filterOpts);
|
||||
}
|
||||
if (dotIdx != -1) {
|
||||
String value = OptionConverter.findAndSubst(key, props);
|
||||
filterOpts.add(new NameValue(name, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort filters by IDs, insantiate filters, set filter options,
|
||||
// add filters to the appender
|
||||
Enumeration g = new SortedKeyEnumeration(filters);
|
||||
while (g.hasMoreElements()) {
|
||||
String key = (String) g.nextElement();
|
||||
String clazz = props.getProperty(key);
|
||||
if (clazz != null) {
|
||||
LogLog.debug("Filter key: ["+key+"] class: ["+props.getProperty(key) +"] props: "+filters.get(key));
|
||||
Filter filter = (Filter) OptionConverter.instantiateByClassName(clazz, Filter.class, null);
|
||||
if (filter != null) {
|
||||
PropertySetter propSetter = new PropertySetter(filter);
|
||||
Vector v = (Vector)filters.get(key);
|
||||
Enumeration filterProps = v.elements();
|
||||
while (filterProps.hasMoreElements()) {
|
||||
NameValue kv = (NameValue)filterProps.nextElement();
|
||||
propSetter.setProperty(kv.key, kv.value);
|
||||
}
|
||||
propSetter.activate();
|
||||
LogLog.debug("Adding filter of type ["+filter.getClass()
|
||||
+"] to appender named ["+appender.getName()+"].");
|
||||
appender.addFilter(filter);
|
||||
}
|
||||
} else {
|
||||
LogLog.warn("Missing class definition for filter: ["+key+"]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void registryPut(Appender appender) {
|
||||
registry.put(appender.getName(), appender);
|
||||
}
|
||||
|
||||
Appender registryGet(String name) {
|
||||
return (Appender) registry.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
class PropertyWatchdog extends FileWatchdog {
|
||||
|
||||
PropertyWatchdog(String filename) {
|
||||
super(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
Call {@link PropertyConfigurator#configure(String)} with the
|
||||
<code>filename</code> to reconfigure log4j. */
|
||||
public
|
||||
void doOnChange() {
|
||||
new PropertyConfigurator().doConfigure(filename,
|
||||
LogManager.getLoggerRepository());
|
||||
}
|
||||
}
|
||||
|
||||
class NameValue {
|
||||
String key, value;
|
||||
public NameValue(String key, String value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
public String toString() {
|
||||
return key + "=" + value;
|
||||
}
|
||||
}
|
||||
|
||||
class SortedKeyEnumeration implements Enumeration {
|
||||
|
||||
private Enumeration e;
|
||||
|
||||
public SortedKeyEnumeration(Hashtable ht) {
|
||||
Enumeration f = ht.keys();
|
||||
Vector keys = new Vector(ht.size());
|
||||
for (int i, last = 0; f.hasMoreElements(); ++last) {
|
||||
String key = (String) f.nextElement();
|
||||
for (i = 0; i < last; ++i) {
|
||||
String s = (String) keys.get(i);
|
||||
if (key.compareTo(s) <= 0) break;
|
||||
}
|
||||
keys.add(i, key);
|
||||
}
|
||||
e = keys.elements();
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return e.hasMoreElements();
|
||||
}
|
||||
|
||||
public Object nextElement() {
|
||||
return e.nextElement();
|
||||
}
|
||||
}
|
||||
29
java/src/org/apache/log4j/ProvisionNode.java
Normal file
29
java/src/org/apache/log4j/ProvisionNode.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
class ProvisionNode extends Vector {
|
||||
private static final long serialVersionUID = -4479121426311014469L;
|
||||
|
||||
ProvisionNode(Logger logger) {
|
||||
super();
|
||||
this.addElement(logger);
|
||||
}
|
||||
}
|
||||
284
java/src/org/apache/log4j/RollingFileAppender.java
Normal file
284
java/src/org/apache/log4j/RollingFileAppender.java
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.io.File;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
import org.apache.log4j.helpers.OptionConverter;
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
import org.apache.log4j.helpers.CountingQuietWriter;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
RollingFileAppender extends FileAppender to backup the log files when
|
||||
they reach a certain size.
|
||||
|
||||
The log4j extras companion includes alternatives which should be considered
|
||||
for new deployments and which are discussed in the documentation
|
||||
for org.apache.log4j.rolling.RollingFileAppender.
|
||||
|
||||
|
||||
@author Heinz Richter
|
||||
@author Ceki Gülcü
|
||||
|
||||
*/
|
||||
public class RollingFileAppender extends FileAppender {
|
||||
|
||||
/**
|
||||
The default maximum file size is 10MB.
|
||||
*/
|
||||
protected long maxFileSize = 10*1024*1024;
|
||||
|
||||
/**
|
||||
There is one backup file by default.
|
||||
*/
|
||||
protected int maxBackupIndex = 1;
|
||||
|
||||
private long nextRollover = 0;
|
||||
|
||||
/**
|
||||
The default constructor simply calls its {@link
|
||||
FileAppender#FileAppender parents constructor}. */
|
||||
public
|
||||
RollingFileAppender() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate a RollingFileAppender and open the file designated by
|
||||
<code>filename</code>. The opened filename will become the ouput
|
||||
destination for this appender.
|
||||
|
||||
<p>If the <code>append</code> parameter is true, the file will be
|
||||
appended to. Otherwise, the file desginated by
|
||||
<code>filename</code> will be truncated before being opened.
|
||||
*/
|
||||
public
|
||||
RollingFileAppender(Layout layout, String filename, boolean append)
|
||||
throws IOException {
|
||||
super(layout, filename, append);
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate a FileAppender and open the file designated by
|
||||
<code>filename</code>. The opened filename will become the output
|
||||
destination for this appender.
|
||||
|
||||
<p>The file will be appended to. */
|
||||
public
|
||||
RollingFileAppender(Layout layout, String filename) throws IOException {
|
||||
super(layout, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the value of the <b>MaxBackupIndex</b> option.
|
||||
*/
|
||||
public
|
||||
int getMaxBackupIndex() {
|
||||
return maxBackupIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the maximum size that the output file is allowed to reach
|
||||
before being rolled over to backup files.
|
||||
|
||||
@since 1.1
|
||||
*/
|
||||
public
|
||||
long getMaximumFileSize() {
|
||||
return maxFileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
Implements the usual roll over behaviour.
|
||||
|
||||
<p>If <code>MaxBackupIndex</code> is positive, then files
|
||||
{<code>File.1</code>, ..., <code>File.MaxBackupIndex -1</code>}
|
||||
are renamed to {<code>File.2</code>, ...,
|
||||
<code>File.MaxBackupIndex</code>}. Moreover, <code>File</code> is
|
||||
renamed <code>File.1</code> and closed. A new <code>File</code> is
|
||||
created to receive further log output.
|
||||
|
||||
<p>If <code>MaxBackupIndex</code> is equal to zero, then the
|
||||
<code>File</code> is truncated with no backup files created.
|
||||
|
||||
*/
|
||||
public // synchronization not necessary since doAppend is alreasy synched
|
||||
void rollOver() {
|
||||
File target;
|
||||
File file;
|
||||
|
||||
if (qw != null) {
|
||||
long size = ((CountingQuietWriter) qw).getCount();
|
||||
LogLog.debug("rolling over count=" + size);
|
||||
// if operation fails, do not roll again until
|
||||
// maxFileSize more bytes are written
|
||||
nextRollover = size + maxFileSize;
|
||||
}
|
||||
LogLog.debug("maxBackupIndex="+maxBackupIndex);
|
||||
|
||||
boolean renameSucceeded = true;
|
||||
// If maxBackups <= 0, then there is no file renaming to be done.
|
||||
if(maxBackupIndex > 0) {
|
||||
// Delete the oldest file, to keep Windows happy.
|
||||
file = new File(fileName + '.' + maxBackupIndex);
|
||||
if (file.exists())
|
||||
renameSucceeded = file.delete();
|
||||
|
||||
// Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
|
||||
for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {
|
||||
file = new File(fileName + "." + i);
|
||||
if (file.exists()) {
|
||||
target = new File(fileName + '.' + (i + 1));
|
||||
LogLog.debug("Renaming file " + file + " to " + target);
|
||||
renameSucceeded = file.renameTo(target);
|
||||
}
|
||||
}
|
||||
|
||||
if(renameSucceeded) {
|
||||
// Rename fileName to fileName.1
|
||||
target = new File(fileName + "." + 1);
|
||||
|
||||
this.closeFile(); // keep windows happy.
|
||||
|
||||
file = new File(fileName);
|
||||
LogLog.debug("Renaming file " + file + " to " + target);
|
||||
renameSucceeded = file.renameTo(target);
|
||||
//
|
||||
// if file rename failed, reopen file with append = true
|
||||
//
|
||||
if (!renameSucceeded) {
|
||||
try {
|
||||
this.setFile(fileName, true, bufferedIO, bufferSize);
|
||||
}
|
||||
catch(IOException e) {
|
||||
if (e instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
LogLog.error("setFile("+fileName+", true) call failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// if all renames were successful, then
|
||||
//
|
||||
if (renameSucceeded) {
|
||||
try {
|
||||
// This will also close the file. This is OK since multiple
|
||||
// close operations are safe.
|
||||
this.setFile(fileName, false, bufferedIO, bufferSize);
|
||||
nextRollover = 0;
|
||||
}
|
||||
catch(IOException e) {
|
||||
if (e instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
LogLog.error("setFile("+fileName+", false) call failed.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
synchronized
|
||||
void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
|
||||
throws IOException {
|
||||
super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
|
||||
if(append) {
|
||||
File f = new File(fileName);
|
||||
((CountingQuietWriter) qw).setCount(f.length());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the maximum number of backup files to keep around.
|
||||
|
||||
<p>The <b>MaxBackupIndex</b> option determines how many backup
|
||||
files are kept before the oldest is erased. This option takes
|
||||
a positive integer value. If set to zero, then there will be no
|
||||
backup files and the log file will be truncated when it reaches
|
||||
<code>MaxFileSize</code>.
|
||||
*/
|
||||
public
|
||||
void setMaxBackupIndex(int maxBackups) {
|
||||
this.maxBackupIndex = maxBackups;
|
||||
}
|
||||
|
||||
/**
|
||||
Set the maximum size that the output file is allowed to reach
|
||||
before being rolled over to backup files.
|
||||
|
||||
<p>This method is equivalent to {@link #setMaxFileSize} except
|
||||
that it is required for differentiating the setter taking a
|
||||
<code>long</code> argument from the setter taking a
|
||||
<code>String</code> argument by the JavaBeans {@link
|
||||
java.beans.Introspector Introspector}.
|
||||
|
||||
@see #setMaxFileSize(String)
|
||||
*/
|
||||
public
|
||||
void setMaximumFileSize(long maxFileSize) {
|
||||
this.maxFileSize = maxFileSize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the maximum size that the output file is allowed to reach
|
||||
before being rolled over to backup files.
|
||||
|
||||
<p>In configuration files, the <b>MaxFileSize</b> option takes an
|
||||
long integer in the range 0 - 2^63. You can specify the value
|
||||
with the suffixes "KB", "MB" or "GB" so that the integer is
|
||||
interpreted being expressed respectively in kilobytes, megabytes
|
||||
or gigabytes. For example, the value "10KB" will be interpreted
|
||||
as 10240.
|
||||
*/
|
||||
public
|
||||
void setMaxFileSize(String value) {
|
||||
maxFileSize = OptionConverter.toFileSize(value, maxFileSize + 1);
|
||||
}
|
||||
|
||||
protected
|
||||
void setQWForFiles(Writer writer) {
|
||||
this.qw = new CountingQuietWriter(writer, errorHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
This method differentiates RollingFileAppender from its super
|
||||
class.
|
||||
|
||||
@since 0.9.0
|
||||
*/
|
||||
protected
|
||||
void subAppend(LoggingEvent event) {
|
||||
super.subAppend(event);
|
||||
if(fileName != null && qw != null) {
|
||||
long size = ((CountingQuietWriter) qw).getCount();
|
||||
if (size >= maxFileSize && size >= nextRollover) {
|
||||
rollOver();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
78
java/src/org/apache/log4j/SimpleLayout.java
Normal file
78
java/src/org/apache/log4j/SimpleLayout.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
SimpleLayout consists of the level of the log statement,
|
||||
followed by " - " and then the log message itself. For example,
|
||||
|
||||
<pre>
|
||||
DEBUG - Hello world
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@author Ceki Gülcü
|
||||
@since version 0.7.0
|
||||
|
||||
<p>{@link PatternLayout} offers a much more powerful alternative.
|
||||
*/
|
||||
public class SimpleLayout extends Layout {
|
||||
|
||||
StringBuffer sbuf = new StringBuffer(128);
|
||||
|
||||
public SimpleLayout() {
|
||||
}
|
||||
|
||||
public
|
||||
void activateOptions() {
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the log statement in a format consisting of the
|
||||
<code>level</code>, followed by " - " and then the
|
||||
<code>message</code>. For example, <pre> INFO - "A message"
|
||||
</pre>
|
||||
|
||||
<p>The <code>category</code> parameter is ignored.
|
||||
<p>
|
||||
@return A byte array in SimpleLayout format.
|
||||
*/
|
||||
public
|
||||
String format(LoggingEvent event) {
|
||||
|
||||
sbuf.setLength(0);
|
||||
sbuf.append(event.getLevel().toString());
|
||||
sbuf.append(" - ");
|
||||
sbuf.append(event.getRenderedMessage());
|
||||
sbuf.append(LINE_SEP);
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
The SimpleLayout does not handle the throwable contained within
|
||||
{@link LoggingEvent LoggingEvents}. Thus, it returns
|
||||
<code>true</code>.
|
||||
|
||||
@since version 0.8.4 */
|
||||
public
|
||||
boolean ignoresThrowable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
217
java/src/org/apache/log4j/TTCCLayout.java
Normal file
217
java/src/org/apache/log4j/TTCCLayout.java
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
// Contributors: Christopher Williams
|
||||
// Mathias Bogaert
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import org.apache.log4j.helpers.DateLayout;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
TTCC layout format consists of time, thread, category and nested
|
||||
diagnostic context information, hence the name.
|
||||
|
||||
<p>Each of the four fields can be individually enabled or
|
||||
disabled. The time format depends on the <code>DateFormat</code>
|
||||
used.
|
||||
|
||||
<p>Here is an example TTCCLayout output with the
|
||||
{@link org.apache.log4j.helpers.RelativeTimeDateFormat}.
|
||||
|
||||
<pre>
|
||||
176 [main] INFO org.apache.log4j.examples.Sort - Populating an array of 2 elements in reverse order.
|
||||
225 [main] INFO org.apache.log4j.examples.SortAlgo - Entered the sort method.
|
||||
262 [main] DEBUG org.apache.log4j.examples.SortAlgo.OUTER i=1 - Outer loop.
|
||||
276 [main] DEBUG org.apache.log4j.examples.SortAlgo.SWAP i=1 j=0 - Swapping intArray[0] = 1 and intArray[1] = 0
|
||||
290 [main] DEBUG org.apache.log4j.examples.SortAlgo.OUTER i=0 - Outer loop.
|
||||
304 [main] INFO org.apache.log4j.examples.SortAlgo.DUMP - Dump of interger array:
|
||||
317 [main] INFO org.apache.log4j.examples.SortAlgo.DUMP - Element [0] = 0
|
||||
331 [main] INFO org.apache.log4j.examples.SortAlgo.DUMP - Element [1] = 1
|
||||
343 [main] INFO org.apache.log4j.examples.Sort - The next log statement should be an error message.
|
||||
346 [main] ERROR org.apache.log4j.examples.SortAlgo.DUMP - Tried to dump an uninitialized array.
|
||||
at org.apache.log4j.examples.SortAlgo.dump(SortAlgo.java:58)
|
||||
at org.apache.log4j.examples.Sort.main(Sort.java:64)
|
||||
467 [main] INFO org.apache.log4j.examples.Sort - Exiting main method.
|
||||
</pre>
|
||||
|
||||
<p>The first field is the number of milliseconds elapsed since the
|
||||
start of the program. The second field is the thread outputting the
|
||||
log statement. The third field is the level, the fourth field is
|
||||
the category to which the statement belongs.
|
||||
|
||||
<p>The fifth field (just before the '-') is the nested diagnostic
|
||||
context. Note the nested diagnostic context may be empty as in the
|
||||
first two statements. The text after the '-' is the message of the
|
||||
statement.
|
||||
|
||||
<p><b>WARNING</b> Do not use the same TTCCLayout instance from
|
||||
within different appenders. The TTCCLayout is not thread safe when
|
||||
used in his way. However, it is perfectly safe to use a TTCCLayout
|
||||
instance from just one appender.
|
||||
|
||||
<p>{@link PatternLayout} offers a much more flexible alternative.
|
||||
|
||||
@author Ceki Gülcü
|
||||
@author <A HREF="mailto:heinz.richter@ecmwf.int">Heinz Richter</a>
|
||||
|
||||
*/
|
||||
public class TTCCLayout extends DateLayout {
|
||||
|
||||
// Internal representation of options
|
||||
private boolean threadPrinting = true;
|
||||
private boolean categoryPrefixing = true;
|
||||
private boolean contextPrinting = true;
|
||||
|
||||
|
||||
protected final StringBuffer buf = new StringBuffer(256);
|
||||
|
||||
|
||||
/**
|
||||
Instantiate a TTCCLayout object with {@link
|
||||
org.apache.log4j.helpers.RelativeTimeDateFormat} as the date
|
||||
formatter in the local time zone.
|
||||
|
||||
@since 0.7.5 */
|
||||
public TTCCLayout() {
|
||||
this.setDateFormat(RELATIVE_TIME_DATE_FORMAT, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Instantiate a TTCCLayout object using the local time zone. The
|
||||
DateFormat used will depend on the <code>dateFormatType</code>.
|
||||
|
||||
<p>This constructor just calls the {@link
|
||||
DateLayout#setDateFormat} method.
|
||||
|
||||
*/
|
||||
public TTCCLayout(String dateFormatType) {
|
||||
this.setDateFormat(dateFormatType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The <b>ThreadPrinting</b> option specifies whether the name of the
|
||||
current thread is part of log output or not. This is true by default.
|
||||
*/
|
||||
public
|
||||
void setThreadPrinting(boolean threadPrinting) {
|
||||
this.threadPrinting = threadPrinting;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns value of the <b>ThreadPrinting</b> option.
|
||||
*/
|
||||
public
|
||||
boolean getThreadPrinting() {
|
||||
return threadPrinting;
|
||||
}
|
||||
|
||||
/**
|
||||
The <b>CategoryPrefixing</b> option specifies whether {@link Category}
|
||||
name is part of log output or not. This is true by default.
|
||||
*/
|
||||
public
|
||||
void setCategoryPrefixing(boolean categoryPrefixing) {
|
||||
this.categoryPrefixing = categoryPrefixing;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns value of the <b>CategoryPrefixing</b> option.
|
||||
*/
|
||||
public
|
||||
boolean getCategoryPrefixing() {
|
||||
return categoryPrefixing;
|
||||
}
|
||||
|
||||
/**
|
||||
The <b>ContextPrinting</b> option specifies log output will include
|
||||
the nested context information belonging to the current thread.
|
||||
This is true by default.
|
||||
*/
|
||||
public
|
||||
void setContextPrinting(boolean contextPrinting) {
|
||||
this.contextPrinting = contextPrinting;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns value of the <b>ContextPrinting</b> option.
|
||||
*/
|
||||
public
|
||||
boolean getContextPrinting() {
|
||||
return contextPrinting;
|
||||
}
|
||||
|
||||
/**
|
||||
In addition to the level of the statement and message, the
|
||||
returned byte array includes time, thread, category and {@link NDC}
|
||||
information.
|
||||
|
||||
<p>Time, thread, category and diagnostic context are printed
|
||||
depending on options.
|
||||
|
||||
@param event The event to format
|
||||
|
||||
*/
|
||||
public
|
||||
String format(LoggingEvent event) {
|
||||
|
||||
// Reset buf
|
||||
buf.setLength(0);
|
||||
|
||||
dateFormat(buf, event);
|
||||
|
||||
if(this.threadPrinting) {
|
||||
buf.append('[');
|
||||
buf.append(event.getThreadName());
|
||||
buf.append("] ");
|
||||
}
|
||||
buf.append(event.getLevel().toString());
|
||||
buf.append(' ');
|
||||
|
||||
if(this.categoryPrefixing) {
|
||||
buf.append(event.getLoggerName());
|
||||
buf.append(' ');
|
||||
}
|
||||
|
||||
if(this.contextPrinting) {
|
||||
String ndc = event.getNDC();
|
||||
|
||||
if(ndc != null) {
|
||||
buf.append(ndc);
|
||||
buf.append(' ');
|
||||
}
|
||||
}
|
||||
buf.append("- ");
|
||||
buf.append(event.getRenderedMessage());
|
||||
buf.append(LINE_SEP);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
The TTCCLayout does not handle the throwable contained within
|
||||
{@link LoggingEvent LoggingEvents}. Thus, it returns
|
||||
<code>true</code>.
|
||||
|
||||
@since version 0.8.4 */
|
||||
public
|
||||
boolean ignoresThrowable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
387
java/src/org/apache/log4j/WriterAppender.java
Normal file
387
java/src/org/apache/log4j/WriterAppender.java
Normal file
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
import org.apache.log4j.helpers.QuietWriter;
|
||||
import org.apache.log4j.spi.ErrorHandler;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
// Contibutors: Jens Uwe Pipka <jens.pipka@gmx.de>
|
||||
// Ben Sandee
|
||||
|
||||
/**
|
||||
WriterAppender appends log events to a {@link java.io.Writer} or an
|
||||
{@link java.io.OutputStream} depending on the user's choice.
|
||||
|
||||
@author Ceki Gülcü
|
||||
@since 1.1 */
|
||||
public class WriterAppender extends AppenderSkeleton {
|
||||
|
||||
|
||||
/**
|
||||
Immediate flush means that the underlying writer or output stream
|
||||
will be flushed at the end of each append operation unless shouldFlush()
|
||||
is overridden. Immediate
|
||||
flush is slower but ensures that each append request is actually
|
||||
written. If <code>immediateFlush</code> is set to
|
||||
<code>false</code>, then there is a good chance that the last few
|
||||
logs events are not actually written to persistent media if and
|
||||
when the application crashes.
|
||||
|
||||
<p>The <code>immediateFlush</code> variable is set to
|
||||
<code>true</code> by default.
|
||||
|
||||
*/
|
||||
protected boolean immediateFlush = true;
|
||||
|
||||
/**
|
||||
The encoding to use when writing. <p>The
|
||||
<code>encoding</code> variable is set to <code>null</null> by
|
||||
default which results in the utilization of the system's default
|
||||
encoding. */
|
||||
protected String encoding;
|
||||
|
||||
/**
|
||||
This is the {@link QuietWriter quietWriter} where we will write
|
||||
to.
|
||||
*/
|
||||
protected QuietWriter qw;
|
||||
|
||||
|
||||
/**
|
||||
This default constructor does nothing. */
|
||||
public
|
||||
WriterAppender() {
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate a WriterAppender and set the output destination to a
|
||||
new {@link OutputStreamWriter} initialized with <code>os</code>
|
||||
as its {@link OutputStream}. */
|
||||
public
|
||||
WriterAppender(Layout layout, OutputStream os) {
|
||||
this(layout, new OutputStreamWriter(os));
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate a WriterAppender and set the output destination to
|
||||
<code>writer</code>.
|
||||
|
||||
<p>The <code>writer</code> must have been previously opened by
|
||||
the user. */
|
||||
public
|
||||
WriterAppender(Layout layout, Writer writer) {
|
||||
this.layout = layout;
|
||||
this.setWriter(writer);
|
||||
}
|
||||
|
||||
/**
|
||||
If the <b>ImmediateFlush</b> option is set to
|
||||
<code>true</code>, the appender will flush at the end of each
|
||||
write. This is the default behavior. If the option is set to
|
||||
<code>false</code>, then the underlying stream can defer writing
|
||||
to physical medium to a later time.
|
||||
|
||||
<p>Avoiding the flush operation at the end of each append results in
|
||||
a performance gain of 10 to 20 percent. However, there is safety
|
||||
tradeoff involved in skipping flushing. Indeed, when flushing is
|
||||
skipped, then it is likely that the last few log events will not
|
||||
be recorded on disk when the application exits. This is a high
|
||||
price to pay even for a 20% performance gain.
|
||||
*/
|
||||
public
|
||||
void setImmediateFlush(boolean value) {
|
||||
immediateFlush = value;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns value of the <b>ImmediateFlush</b> option.
|
||||
*/
|
||||
public
|
||||
boolean getImmediateFlush() {
|
||||
return immediateFlush;
|
||||
}
|
||||
|
||||
/**
|
||||
Does nothing.
|
||||
*/
|
||||
public
|
||||
void activateOptions() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This method is called by the {@link AppenderSkeleton#doAppend}
|
||||
method.
|
||||
|
||||
<p>If the output stream exists and is writable then write a log
|
||||
statement to the output stream. Otherwise, write a single warning
|
||||
message to <code>System.err</code>.
|
||||
|
||||
<p>The format of the output will depend on this appender's
|
||||
layout.
|
||||
|
||||
*/
|
||||
public
|
||||
void append(LoggingEvent event) {
|
||||
|
||||
// Reminder: the nesting of calls is:
|
||||
//
|
||||
// doAppend()
|
||||
// - check threshold
|
||||
// - filter
|
||||
// - append();
|
||||
// - checkEntryConditions();
|
||||
// - subAppend();
|
||||
|
||||
if(!checkEntryConditions()) {
|
||||
return;
|
||||
}
|
||||
subAppend(event);
|
||||
}
|
||||
|
||||
/**
|
||||
This method determines if there is a sense in attempting to append.
|
||||
|
||||
<p>It checks whether there is a set output target and also if
|
||||
there is a set layout. If these checks fail, then the boolean
|
||||
value <code>false</code> is returned. */
|
||||
protected
|
||||
boolean checkEntryConditions() {
|
||||
if(this.closed) {
|
||||
LogLog.warn("Not allowed to write to a closed appender.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(this.qw == null) {
|
||||
errorHandler.error("No output stream or file set for the appender named ["+
|
||||
name+"].");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(this.layout == null) {
|
||||
errorHandler.error("No layout set for the appender named ["+ name+"].");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Close this appender instance. The underlying stream or writer is
|
||||
also closed.
|
||||
|
||||
<p>Closed appenders cannot be reused.
|
||||
|
||||
@see #setWriter
|
||||
@since 0.8.4 */
|
||||
public
|
||||
synchronized
|
||||
void close() {
|
||||
if(this.closed)
|
||||
return;
|
||||
this.closed = true;
|
||||
writeFooter();
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the underlying {@link java.io.Writer}.
|
||||
* */
|
||||
protected void closeWriter() {
|
||||
if(qw != null) {
|
||||
try {
|
||||
qw.close();
|
||||
} catch(IOException e) {
|
||||
if (e instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
// There is do need to invoke an error handler at this late
|
||||
// stage.
|
||||
LogLog.error("Could not close " + qw, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an OutputStreamWriter when passed an OutputStream. The
|
||||
encoding used will depend on the value of the
|
||||
<code>encoding</code> property. If the encoding value is
|
||||
specified incorrectly the writer will be opened using the default
|
||||
system encoding (an error message will be printed to the loglog. */
|
||||
protected
|
||||
OutputStreamWriter createWriter(OutputStream os) {
|
||||
OutputStreamWriter retval = null;
|
||||
|
||||
String enc = getEncoding();
|
||||
if(enc != null) {
|
||||
try {
|
||||
retval = new OutputStreamWriter(os, enc);
|
||||
} catch(IOException e) {
|
||||
if (e instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
LogLog.warn("Error initializing output writer.");
|
||||
LogLog.warn("Unsupported encoding?");
|
||||
}
|
||||
}
|
||||
if(retval == null) {
|
||||
retval = new OutputStreamWriter(os);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
public String getEncoding() {
|
||||
return encoding;
|
||||
}
|
||||
|
||||
public void setEncoding(String value) {
|
||||
encoding = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Set the {@link ErrorHandler} for this WriterAppender and also the
|
||||
underlying {@link QuietWriter} if any. */
|
||||
public synchronized void setErrorHandler(ErrorHandler eh) {
|
||||
if(eh == null) {
|
||||
LogLog.warn("You have tried to set a null error-handler.");
|
||||
} else {
|
||||
this.errorHandler = eh;
|
||||
if(this.qw != null) {
|
||||
this.qw.setErrorHandler(eh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
<p>Sets the Writer where the log output will go. The
|
||||
specified Writer must be opened by the user and be
|
||||
writable.
|
||||
|
||||
<p>The <code>java.io.Writer</code> will be closed when the
|
||||
appender instance is closed.
|
||||
|
||||
|
||||
<p><b>WARNING:</b> Logging to an unopened Writer will fail.
|
||||
<p>
|
||||
@param writer An already opened Writer. */
|
||||
public synchronized void setWriter(Writer writer) {
|
||||
reset();
|
||||
this.qw = new QuietWriter(writer, errorHandler);
|
||||
//this.tp = new TracerPrintWriter(qw);
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Actual writing occurs here.
|
||||
|
||||
<p>Most subclasses of <code>WriterAppender</code> will need to
|
||||
override this method.
|
||||
|
||||
@since 0.9.0 */
|
||||
protected
|
||||
void subAppend(LoggingEvent event) {
|
||||
this.qw.write(this.layout.format(event));
|
||||
|
||||
if(layout.ignoresThrowable()) {
|
||||
String[] s = event.getThrowableStrRep();
|
||||
if (s != null) {
|
||||
int len = s.length;
|
||||
for(int i = 0; i < len; i++) {
|
||||
this.qw.write(s[i]);
|
||||
this.qw.write(Layout.LINE_SEP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(shouldFlush(event)) {
|
||||
this.qw.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
The WriterAppender requires a layout. Hence, this method returns
|
||||
<code>true</code>.
|
||||
*/
|
||||
public
|
||||
boolean requiresLayout() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Clear internal references to the writer and other variables.
|
||||
|
||||
Subclasses can override this method for an alternate closing
|
||||
behavior. */
|
||||
protected
|
||||
void reset() {
|
||||
closeWriter();
|
||||
this.qw = null;
|
||||
//this.tp = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Write a footer as produced by the embedded layout's {@link
|
||||
Layout#getFooter} method. */
|
||||
protected
|
||||
void writeFooter() {
|
||||
if(layout != null) {
|
||||
String f = layout.getFooter();
|
||||
if(f != null && this.qw != null) {
|
||||
this.qw.write(f);
|
||||
this.qw.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Write a header as produced by the embedded layout's {@link
|
||||
Layout#getHeader} method. */
|
||||
protected
|
||||
void writeHeader() {
|
||||
if(layout != null) {
|
||||
String h = layout.getHeader();
|
||||
if(h != null && this.qw != null)
|
||||
this.qw.write(h);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the writer should be flushed after
|
||||
* this event is written.
|
||||
*
|
||||
* @since 1.2.16
|
||||
*/
|
||||
protected boolean shouldFlush(final LoggingEvent event) {
|
||||
return immediateFlush;
|
||||
}
|
||||
}
|
||||
222
java/src/org/apache/log4j/chainsaw/ControlPanel.java
Normal file
222
java/src/org/apache/log4j/chainsaw/ControlPanel.java
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.chainsaw;
|
||||
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.Priority;
|
||||
import org.apache.log4j.Level;
|
||||
|
||||
/**
|
||||
* Represents the controls for filtering, pausing, exiting, etc.
|
||||
*
|
||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
||||
*/
|
||||
class ControlPanel extends JPanel {
|
||||
/** use the log messages **/
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ControlPanel.class);
|
||||
|
||||
/**
|
||||
* Creates a new <code>ControlPanel</code> instance.
|
||||
*
|
||||
* @param aModel the model to control
|
||||
*/
|
||||
ControlPanel(final MyTableModel aModel) {
|
||||
setBorder(BorderFactory.createTitledBorder("Controls: "));
|
||||
final GridBagLayout gridbag = new GridBagLayout();
|
||||
final GridBagConstraints c = new GridBagConstraints();
|
||||
setLayout(gridbag);
|
||||
|
||||
// Pad everything
|
||||
c.ipadx = 5;
|
||||
c.ipady = 5;
|
||||
|
||||
// Add the 1st column of labels
|
||||
c.gridx = 0;
|
||||
c.anchor = GridBagConstraints.EAST;
|
||||
|
||||
c.gridy = 0;
|
||||
JLabel label = new JLabel("Filter Level:");
|
||||
gridbag.setConstraints(label, c);
|
||||
add(label);
|
||||
|
||||
c.gridy++;
|
||||
label = new JLabel("Filter Thread:");
|
||||
gridbag.setConstraints(label, c);
|
||||
add(label);
|
||||
|
||||
c.gridy++;
|
||||
label = new JLabel("Filter Logger:");
|
||||
gridbag.setConstraints(label, c);
|
||||
add(label);
|
||||
|
||||
c.gridy++;
|
||||
label = new JLabel("Filter NDC:");
|
||||
gridbag.setConstraints(label, c);
|
||||
add(label);
|
||||
|
||||
c.gridy++;
|
||||
label = new JLabel("Filter Message:");
|
||||
gridbag.setConstraints(label, c);
|
||||
add(label);
|
||||
|
||||
// Add the 2nd column of filters
|
||||
c.weightx = 1;
|
||||
//c.weighty = 1;
|
||||
c.gridx = 1;
|
||||
c.anchor = GridBagConstraints.WEST;
|
||||
|
||||
c.gridy = 0;
|
||||
final Level[] allPriorities = new Level[] {Level.FATAL,
|
||||
Level.ERROR,
|
||||
Level.WARN,
|
||||
Level.INFO,
|
||||
Level.DEBUG,
|
||||
Level.TRACE };
|
||||
|
||||
final JComboBox priorities = new JComboBox(allPriorities);
|
||||
final Level lowest = allPriorities[allPriorities.length - 1];
|
||||
priorities.setSelectedItem(lowest);
|
||||
aModel.setPriorityFilter(lowest);
|
||||
gridbag.setConstraints(priorities, c);
|
||||
add(priorities);
|
||||
priorities.setEditable(false);
|
||||
priorities.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent aEvent) {
|
||||
aModel.setPriorityFilter(
|
||||
(Priority) priorities.getSelectedItem());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.gridy++;
|
||||
final JTextField threadField = new JTextField("");
|
||||
threadField.getDocument().addDocumentListener(new DocumentListener () {
|
||||
public void insertUpdate(DocumentEvent aEvent) {
|
||||
aModel.setThreadFilter(threadField.getText());
|
||||
}
|
||||
public void removeUpdate(DocumentEvent aEvente) {
|
||||
aModel.setThreadFilter(threadField.getText());
|
||||
}
|
||||
public void changedUpdate(DocumentEvent aEvent) {
|
||||
aModel.setThreadFilter(threadField.getText());
|
||||
}
|
||||
});
|
||||
gridbag.setConstraints(threadField, c);
|
||||
add(threadField);
|
||||
|
||||
c.gridy++;
|
||||
final JTextField catField = new JTextField("");
|
||||
catField.getDocument().addDocumentListener(new DocumentListener () {
|
||||
public void insertUpdate(DocumentEvent aEvent) {
|
||||
aModel.setCategoryFilter(catField.getText());
|
||||
}
|
||||
public void removeUpdate(DocumentEvent aEvent) {
|
||||
aModel.setCategoryFilter(catField.getText());
|
||||
}
|
||||
public void changedUpdate(DocumentEvent aEvent) {
|
||||
aModel.setCategoryFilter(catField.getText());
|
||||
}
|
||||
});
|
||||
gridbag.setConstraints(catField, c);
|
||||
add(catField);
|
||||
|
||||
c.gridy++;
|
||||
final JTextField ndcField = new JTextField("");
|
||||
ndcField.getDocument().addDocumentListener(new DocumentListener () {
|
||||
public void insertUpdate(DocumentEvent aEvent) {
|
||||
aModel.setNDCFilter(ndcField.getText());
|
||||
}
|
||||
public void removeUpdate(DocumentEvent aEvent) {
|
||||
aModel.setNDCFilter(ndcField.getText());
|
||||
}
|
||||
public void changedUpdate(DocumentEvent aEvent) {
|
||||
aModel.setNDCFilter(ndcField.getText());
|
||||
}
|
||||
});
|
||||
gridbag.setConstraints(ndcField, c);
|
||||
add(ndcField);
|
||||
|
||||
c.gridy++;
|
||||
final JTextField msgField = new JTextField("");
|
||||
msgField.getDocument().addDocumentListener(new DocumentListener () {
|
||||
public void insertUpdate(DocumentEvent aEvent) {
|
||||
aModel.setMessageFilter(msgField.getText());
|
||||
}
|
||||
public void removeUpdate(DocumentEvent aEvent) {
|
||||
aModel.setMessageFilter(msgField.getText());
|
||||
}
|
||||
public void changedUpdate(DocumentEvent aEvent) {
|
||||
aModel.setMessageFilter(msgField.getText());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
gridbag.setConstraints(msgField, c);
|
||||
add(msgField);
|
||||
|
||||
// Add the 3rd column of buttons
|
||||
c.weightx = 0;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.anchor = GridBagConstraints.EAST;
|
||||
c.gridx = 2;
|
||||
|
||||
c.gridy = 0;
|
||||
final JButton exitButton = new JButton("Exit");
|
||||
exitButton.setMnemonic('x');
|
||||
exitButton.addActionListener(ExitAction.INSTANCE);
|
||||
gridbag.setConstraints(exitButton, c);
|
||||
add(exitButton);
|
||||
|
||||
c.gridy++;
|
||||
final JButton clearButton = new JButton("Clear");
|
||||
clearButton.setMnemonic('c');
|
||||
clearButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent aEvent) {
|
||||
aModel.clear();
|
||||
}
|
||||
});
|
||||
gridbag.setConstraints(clearButton, c);
|
||||
add(clearButton);
|
||||
|
||||
c.gridy++;
|
||||
final JButton toggleButton = new JButton("Pause");
|
||||
toggleButton.setMnemonic('p');
|
||||
toggleButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent aEvent) {
|
||||
aModel.toggle();
|
||||
toggleButton.setText(
|
||||
aModel.isPaused() ? "Resume" : "Pause");
|
||||
}
|
||||
});
|
||||
gridbag.setConstraints(toggleButton, c);
|
||||
add(toggleButton);
|
||||
}
|
||||
}
|
||||
170
java/src/org/apache/log4j/chainsaw/DetailPanel.java
Normal file
170
java/src/org/apache/log4j/chainsaw/DetailPanel.java
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.chainsaw;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Date;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* A panel for showing a stack trace.
|
||||
*
|
||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
||||
*/
|
||||
class DetailPanel
|
||||
extends JPanel
|
||||
implements ListSelectionListener
|
||||
{
|
||||
/** used to log events **/
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(DetailPanel.class);
|
||||
|
||||
/** used to format the logging event **/
|
||||
private static final MessageFormat FORMATTER = new MessageFormat(
|
||||
"<b>Time:</b> <code>{0,time,medium}</code>" +
|
||||
" <b>Priority:</b> <code>{1}</code>" +
|
||||
" <b>Thread:</b> <code>{2}</code>" +
|
||||
" <b>NDC:</b> <code>{3}</code>" +
|
||||
"<br><b>Logger:</b> <code>{4}</code>" +
|
||||
"<br><b>Location:</b> <code>{5}</code>" +
|
||||
"<br><b>Message:</b>" +
|
||||
"<pre>{6}</pre>" +
|
||||
"<b>Throwable:</b>" +
|
||||
"<pre>{7}</pre>");
|
||||
|
||||
/** the model for the data to render **/
|
||||
private final MyTableModel mModel;
|
||||
/** pane for rendering detail **/
|
||||
private final JEditorPane mDetails;
|
||||
|
||||
/**
|
||||
* Creates a new <code>DetailPanel</code> instance.
|
||||
*
|
||||
* @param aTable the table to listen for selections on
|
||||
* @param aModel the model backing the table
|
||||
*/
|
||||
DetailPanel(JTable aTable, final MyTableModel aModel) {
|
||||
mModel = aModel;
|
||||
setLayout(new BorderLayout());
|
||||
setBorder(BorderFactory.createTitledBorder("Details: "));
|
||||
|
||||
mDetails = new JEditorPane();
|
||||
mDetails.setEditable(false);
|
||||
mDetails.setContentType("text/html");
|
||||
add(new JScrollPane(mDetails), BorderLayout.CENTER);
|
||||
|
||||
final ListSelectionModel rowSM = aTable.getSelectionModel();
|
||||
rowSM.addListSelectionListener(this);
|
||||
}
|
||||
|
||||
/** @see ListSelectionListener **/
|
||||
public void valueChanged(ListSelectionEvent aEvent) {
|
||||
//Ignore extra messages.
|
||||
if (aEvent.getValueIsAdjusting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ListSelectionModel lsm = (ListSelectionModel) aEvent.getSource();
|
||||
if (lsm.isSelectionEmpty()) {
|
||||
mDetails.setText("Nothing selected");
|
||||
} else {
|
||||
final int selectedRow = lsm.getMinSelectionIndex();
|
||||
final EventDetails e = mModel.getEventDetails(selectedRow);
|
||||
final Object[] args =
|
||||
{
|
||||
new Date(e.getTimeStamp()),
|
||||
e.getPriority(),
|
||||
escape(e.getThreadName()),
|
||||
escape(e.getNDC()),
|
||||
escape(e.getCategoryName()),
|
||||
escape(e.getLocationDetails()),
|
||||
escape(e.getMessage()),
|
||||
escape(getThrowableStrRep(e))
|
||||
};
|
||||
mDetails.setText(FORMATTER.format(args));
|
||||
mDetails.setCaretPosition(0);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Private methods
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Returns a string representation of a throwable.
|
||||
*
|
||||
* @param aEvent contains the throwable information
|
||||
* @return a <code>String</code> value
|
||||
*/
|
||||
private static String getThrowableStrRep(EventDetails aEvent) {
|
||||
final String[] strs = aEvent.getThrowableStrRep();
|
||||
if (strs == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < strs.length; i++) {
|
||||
sb.append(strs[i]).append("\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape <, > & and " as their entities. It is very
|
||||
* dumb about & handling.
|
||||
* @param aStr the String to escape.
|
||||
* @return the escaped String
|
||||
*/
|
||||
private String escape(String aStr) {
|
||||
if (aStr == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < aStr.length(); i++) {
|
||||
char c = aStr.charAt(i);
|
||||
switch (c) {
|
||||
case '<':
|
||||
buf.append("<");
|
||||
break;
|
||||
case '>':
|
||||
buf.append(">");
|
||||
break;
|
||||
case '\"':
|
||||
buf.append(""");
|
||||
break;
|
||||
case '&':
|
||||
buf.append("&");
|
||||
break;
|
||||
default:
|
||||
buf.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
135
java/src/org/apache/log4j/chainsaw/EventDetails.java
Normal file
135
java/src/org/apache/log4j/chainsaw/EventDetails.java
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.chainsaw;
|
||||
|
||||
import org.apache.log4j.Priority;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
* Represents the details of a logging event. It is intended to overcome the
|
||||
* problem that a LoggingEvent cannot be constructed with purely fake data.
|
||||
*
|
||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
||||
* @version 1.0
|
||||
*/
|
||||
class EventDetails {
|
||||
|
||||
/** the time of the event **/
|
||||
private final long mTimeStamp;
|
||||
/** the priority of the event **/
|
||||
private final Priority mPriority;
|
||||
/** the category of the event **/
|
||||
private final String mCategoryName;
|
||||
/** the NDC for the event **/
|
||||
private final String mNDC;
|
||||
/** the thread for the event **/
|
||||
private final String mThreadName;
|
||||
/** the msg for the event **/
|
||||
private final String mMessage;
|
||||
/** the throwable details the event **/
|
||||
private final String[] mThrowableStrRep;
|
||||
/** the location details for the event **/
|
||||
private final String mLocationDetails;
|
||||
|
||||
/**
|
||||
* Creates a new <code>EventDetails</code> instance.
|
||||
* @param aTimeStamp a <code>long</code> value
|
||||
* @param aPriority a <code>Priority</code> value
|
||||
* @param aCategoryName a <code>String</code> value
|
||||
* @param aNDC a <code>String</code> value
|
||||
* @param aThreadName a <code>String</code> value
|
||||
* @param aMessage a <code>String</code> value
|
||||
* @param aThrowableStrRep a <code>String[]</code> value
|
||||
* @param aLocationDetails a <code>String</code> value
|
||||
*/
|
||||
EventDetails(long aTimeStamp,
|
||||
Priority aPriority,
|
||||
String aCategoryName,
|
||||
String aNDC,
|
||||
String aThreadName,
|
||||
String aMessage,
|
||||
String[] aThrowableStrRep,
|
||||
String aLocationDetails)
|
||||
{
|
||||
mTimeStamp = aTimeStamp;
|
||||
mPriority = aPriority;
|
||||
mCategoryName = aCategoryName;
|
||||
mNDC = aNDC;
|
||||
mThreadName = aThreadName;
|
||||
mMessage = aMessage;
|
||||
mThrowableStrRep = aThrowableStrRep;
|
||||
mLocationDetails = aLocationDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>EventDetails</code> instance.
|
||||
*
|
||||
* @param aEvent a <code>LoggingEvent</code> value
|
||||
*/
|
||||
EventDetails(LoggingEvent aEvent) {
|
||||
|
||||
this(aEvent.timeStamp,
|
||||
aEvent.getLevel(),
|
||||
aEvent.getLoggerName(),
|
||||
aEvent.getNDC(),
|
||||
aEvent.getThreadName(),
|
||||
aEvent.getRenderedMessage(),
|
||||
aEvent.getThrowableStrRep(),
|
||||
(aEvent.getLocationInformation() == null)
|
||||
? null : aEvent.getLocationInformation().fullInfo);
|
||||
}
|
||||
|
||||
/** @see #mTimeStamp **/
|
||||
long getTimeStamp() {
|
||||
return mTimeStamp;
|
||||
}
|
||||
|
||||
/** @see #mPriority **/
|
||||
Priority getPriority() {
|
||||
return mPriority;
|
||||
}
|
||||
|
||||
/** @see #mCategoryName **/
|
||||
String getCategoryName() {
|
||||
return mCategoryName;
|
||||
}
|
||||
|
||||
/** @see #mNDC **/
|
||||
String getNDC() {
|
||||
return mNDC;
|
||||
}
|
||||
|
||||
/** @see #mThreadName **/
|
||||
String getThreadName() {
|
||||
return mThreadName;
|
||||
}
|
||||
|
||||
/** @see #mMessage **/
|
||||
String getMessage() {
|
||||
return mMessage;
|
||||
}
|
||||
|
||||
/** @see #mLocationDetails **/
|
||||
String getLocationDetails(){
|
||||
return mLocationDetails;
|
||||
}
|
||||
|
||||
/** @see #mThrowableStrRep **/
|
||||
String[] getThrowableStrRep() {
|
||||
return mThrowableStrRep;
|
||||
}
|
||||
}
|
||||
48
java/src/org/apache/log4j/chainsaw/ExitAction.java
Normal file
48
java/src/org/apache/log4j/chainsaw/ExitAction.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.chainsaw;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Encapsulates the action to exit.
|
||||
*
|
||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
||||
* @version 1.0
|
||||
*/
|
||||
class ExitAction
|
||||
extends AbstractAction
|
||||
{
|
||||
/** use to log messages **/
|
||||
private static final Logger LOG = Logger.getLogger(ExitAction.class);
|
||||
/** The instance to share **/
|
||||
public static final ExitAction INSTANCE = new ExitAction();
|
||||
|
||||
/** Stop people creating instances **/
|
||||
private ExitAction() {}
|
||||
|
||||
/**
|
||||
* Will shutdown the application.
|
||||
* @param aIgnore ignored
|
||||
*/
|
||||
public void actionPerformed(ActionEvent aIgnore) {
|
||||
LOG.info("shutting down");
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
139
java/src/org/apache/log4j/chainsaw/LoadXMLAction.java
Normal file
139
java/src/org/apache/log4j/chainsaw/LoadXMLAction.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.chainsaw;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
/**
|
||||
* Encapsulates the action to load an XML file.
|
||||
*
|
||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
||||
* @version 1.0
|
||||
*/
|
||||
class LoadXMLAction
|
||||
extends AbstractAction
|
||||
{
|
||||
/** use to log messages **/
|
||||
private static final Logger LOG = Logger.getLogger(LoadXMLAction.class);
|
||||
|
||||
/** the parent frame **/
|
||||
private final JFrame mParent;
|
||||
|
||||
/**
|
||||
* the file chooser - configured to allow only the selection of a
|
||||
* single file.
|
||||
*/
|
||||
private final JFileChooser mChooser = new JFileChooser();
|
||||
{
|
||||
mChooser.setMultiSelectionEnabled(false);
|
||||
mChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
}
|
||||
|
||||
/** parser to read XML files **/
|
||||
private final XMLReader mParser;
|
||||
/** the content handler **/
|
||||
private final XMLFileHandler mHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new <code>LoadXMLAction</code> instance.
|
||||
*
|
||||
* @param aParent the parent frame
|
||||
* @param aModel the model to add events to
|
||||
* @exception SAXException if an error occurs
|
||||
* @throws ParserConfigurationException if an error occurs
|
||||
*/
|
||||
LoadXMLAction(JFrame aParent, MyTableModel aModel)
|
||||
throws SAXException, ParserConfigurationException
|
||||
{
|
||||
mParent = aParent;
|
||||
mHandler = new XMLFileHandler(aModel);
|
||||
mParser = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
|
||||
mParser.setContentHandler(mHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user for a file to load events from.
|
||||
* @param aIgnore an <code>ActionEvent</code> value
|
||||
*/
|
||||
public void actionPerformed(ActionEvent aIgnore) {
|
||||
LOG.info("load file called");
|
||||
if (mChooser.showOpenDialog(mParent) == JFileChooser.APPROVE_OPTION) {
|
||||
LOG.info("Need to load a file");
|
||||
final File chosen = mChooser.getSelectedFile();
|
||||
LOG.info("loading the contents of " + chosen.getAbsolutePath());
|
||||
try {
|
||||
final int num = loadFile(chosen.getAbsolutePath());
|
||||
JOptionPane.showMessageDialog(
|
||||
mParent,
|
||||
"Loaded " + num + " events.",
|
||||
"CHAINSAW",
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
} catch (Exception e) {
|
||||
LOG.warn("caught an exception loading the file", e);
|
||||
JOptionPane.showMessageDialog(
|
||||
mParent,
|
||||
"Error parsing file - " + e.getMessage(),
|
||||
"CHAINSAW",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the contents of file into the model
|
||||
*
|
||||
* @param aFile the file to extract events from
|
||||
* @return the number of events loaded
|
||||
* @throws SAXException if an error occurs
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
private int loadFile(String aFile)
|
||||
throws SAXException, IOException
|
||||
{
|
||||
synchronized (mParser) {
|
||||
// Create a dummy document to parse the file
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
buf.append("<?xml version=\"1.0\" standalone=\"yes\"?>\n");
|
||||
buf.append("<!DOCTYPE log4j:eventSet ");
|
||||
buf.append("[<!ENTITY data SYSTEM \"file:///");
|
||||
buf.append(aFile);
|
||||
buf.append("\">]>\n");
|
||||
buf.append("<log4j:eventSet xmlns:log4j=\"Claira\">\n");
|
||||
buf.append("&data;\n");
|
||||
buf.append("</log4j:eventSet>\n");
|
||||
|
||||
final InputSource is =
|
||||
new InputSource(new StringReader(buf.toString()));
|
||||
mParser.parse(is);
|
||||
return mHandler.getNumEvents();
|
||||
}
|
||||
}
|
||||
}
|
||||
121
java/src/org/apache/log4j/chainsaw/LoggingReceiver.java
Normal file
121
java/src/org/apache/log4j/chainsaw/LoggingReceiver.java
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.chainsaw;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
* A daemon thread the processes connections from a
|
||||
* <code>org.apache.log4j.net.SocketAppender.html</code>.
|
||||
*
|
||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
||||
*/
|
||||
class LoggingReceiver extends Thread {
|
||||
/** used to log messages **/
|
||||
private static final Logger LOG = Logger.getLogger(LoggingReceiver.class);
|
||||
|
||||
/**
|
||||
* Helper that actually processes a client connection. It receives events
|
||||
* and adds them to the supplied model.
|
||||
*
|
||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
||||
*/
|
||||
private class Slurper implements Runnable {
|
||||
/** socket connection to read events from **/
|
||||
private final Socket mClient;
|
||||
|
||||
/**
|
||||
* Creates a new <code>Slurper</code> instance.
|
||||
*
|
||||
* @param aClient socket to receive events from
|
||||
*/
|
||||
Slurper(Socket aClient) {
|
||||
mClient = aClient;
|
||||
}
|
||||
|
||||
/** loops getting the events **/
|
||||
public void run() {
|
||||
LOG.debug("Starting to get data");
|
||||
try {
|
||||
final ObjectInputStream ois =
|
||||
new ObjectInputStream(mClient.getInputStream());
|
||||
while (true) {
|
||||
final LoggingEvent event = (LoggingEvent) ois.readObject();
|
||||
mModel.addEvent(new EventDetails(event));
|
||||
}
|
||||
} catch (EOFException e) {
|
||||
LOG.info("Reached EOF, closing connection");
|
||||
} catch (SocketException e) {
|
||||
LOG.info("Caught SocketException, closing connection");
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Got IOException, closing connection", e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOG.warn("Got ClassNotFoundException, closing connection", e);
|
||||
}
|
||||
|
||||
try {
|
||||
mClient.close();
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Error closing connection", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** where to put the events **/
|
||||
private MyTableModel mModel;
|
||||
|
||||
/** server for listening for connections **/
|
||||
private ServerSocket mSvrSock;
|
||||
|
||||
/**
|
||||
* Creates a new <code>LoggingReceiver</code> instance.
|
||||
*
|
||||
* @param aModel model to place put received into
|
||||
* @param aPort port to listen on
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
LoggingReceiver(MyTableModel aModel, int aPort) throws IOException {
|
||||
setDaemon(true);
|
||||
mModel = aModel;
|
||||
mSvrSock = new ServerSocket(aPort);
|
||||
}
|
||||
|
||||
/** Listens for client connections **/
|
||||
public void run() {
|
||||
LOG.info("Thread started");
|
||||
try {
|
||||
while (true) {
|
||||
LOG.debug("Waiting for a connection");
|
||||
final Socket client = mSvrSock.accept();
|
||||
LOG.debug("Got a connection from " +
|
||||
client.getInetAddress().getHostName());
|
||||
final Thread t = new Thread(new Slurper(client));
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Error in accepting connections, stopping.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
192
java/src/org/apache/log4j/chainsaw/Main.java
Normal file
192
java/src/org/apache/log4j/chainsaw/Main.java
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.chainsaw;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
|
||||
/**
|
||||
* The main application.
|
||||
*
|
||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
||||
*/
|
||||
public class Main
|
||||
extends JFrame
|
||||
{
|
||||
/** the default port number to listen on **/
|
||||
private static final int DEFAULT_PORT = 4445;
|
||||
|
||||
/** name of property for port name **/
|
||||
public static final String PORT_PROP_NAME = "chainsaw.port";
|
||||
|
||||
/** use to log messages **/
|
||||
private static final Logger LOG = Logger.getLogger(Main.class);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new <code>Main</code> instance.
|
||||
*/
|
||||
private Main() {
|
||||
super("CHAINSAW - Log4J Log Viewer");
|
||||
// create the all important model
|
||||
final MyTableModel model = new MyTableModel();
|
||||
|
||||
//Create the menu bar.
|
||||
final JMenuBar menuBar = new JMenuBar();
|
||||
setJMenuBar(menuBar);
|
||||
final JMenu menu = new JMenu("File");
|
||||
menuBar.add(menu);
|
||||
|
||||
try {
|
||||
final LoadXMLAction lxa = new LoadXMLAction(this, model);
|
||||
final JMenuItem loadMenuItem = new JMenuItem("Load file...");
|
||||
menu.add(loadMenuItem);
|
||||
loadMenuItem.addActionListener(lxa);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
LOG.info("Missing classes for XML parser", e);
|
||||
JOptionPane.showMessageDialog(
|
||||
this,
|
||||
"XML parser not in classpath - unable to load XML events.",
|
||||
"CHAINSAW",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (Exception e) {
|
||||
LOG.info("Unable to create the action to load XML files", e);
|
||||
JOptionPane.showMessageDialog(
|
||||
this,
|
||||
"Unable to create a XML parser - unable to load XML events.",
|
||||
"CHAINSAW",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
final JMenuItem exitMenuItem = new JMenuItem("Exit");
|
||||
menu.add(exitMenuItem);
|
||||
exitMenuItem.addActionListener(ExitAction.INSTANCE);
|
||||
|
||||
// Add control panel
|
||||
final ControlPanel cp = new ControlPanel(model);
|
||||
getContentPane().add(cp, BorderLayout.NORTH);
|
||||
|
||||
// Create the table
|
||||
final JTable table = new JTable(model);
|
||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
final JScrollPane scrollPane = new JScrollPane(table);
|
||||
scrollPane.setBorder(BorderFactory.createTitledBorder("Events: "));
|
||||
scrollPane.setPreferredSize(new Dimension(900, 300));
|
||||
|
||||
// Create the details
|
||||
final JPanel details = new DetailPanel(table, model);
|
||||
details.setPreferredSize(new Dimension(900, 300));
|
||||
|
||||
// Add the table and stack trace into a splitter
|
||||
final JSplitPane jsp =
|
||||
new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, details);
|
||||
getContentPane().add(jsp, BorderLayout.CENTER);
|
||||
|
||||
addWindowListener(new WindowAdapter() {
|
||||
public void windowClosing(WindowEvent aEvent) {
|
||||
ExitAction.INSTANCE.actionPerformed(null);
|
||||
}
|
||||
});
|
||||
|
||||
pack();
|
||||
setVisible(true);
|
||||
|
||||
setupReceiver(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup recieving messages.
|
||||
*
|
||||
* @param aModel a <code>MyTableModel</code> value
|
||||
*/
|
||||
private void setupReceiver(MyTableModel aModel) {
|
||||
int port = DEFAULT_PORT;
|
||||
final String strRep = System.getProperty(PORT_PROP_NAME);
|
||||
if (strRep != null) {
|
||||
try {
|
||||
port = Integer.parseInt(strRep);
|
||||
} catch (NumberFormatException nfe) {
|
||||
LOG.fatal("Unable to parse " + PORT_PROP_NAME +
|
||||
" property with value " + strRep + ".");
|
||||
JOptionPane.showMessageDialog(
|
||||
this,
|
||||
"Unable to parse port number from '" + strRep +
|
||||
"', quitting.",
|
||||
"CHAINSAW",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
final LoggingReceiver lr = new LoggingReceiver(aModel, port);
|
||||
lr.start();
|
||||
} catch (IOException e) {
|
||||
LOG.fatal("Unable to connect to socket server, quiting", e);
|
||||
JOptionPane.showMessageDialog(
|
||||
this,
|
||||
"Unable to create socket on port " + port + ", quitting.",
|
||||
"CHAINSAW",
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// static methods
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/** initialise log4j **/
|
||||
private static void initLog4J() {
|
||||
final Properties props = new Properties();
|
||||
props.setProperty("log4j.rootLogger", "DEBUG, A1");
|
||||
props.setProperty("log4j.appender.A1",
|
||||
"org.apache.log4j.ConsoleAppender");
|
||||
props.setProperty("log4j.appender.A1.layout",
|
||||
"org.apache.log4j.TTCCLayout");
|
||||
PropertyConfigurator.configure(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method.
|
||||
*
|
||||
* @param aArgs ignored
|
||||
*/
|
||||
public static void main(String[] aArgs) {
|
||||
initLog4J();
|
||||
new Main();
|
||||
}
|
||||
}
|
||||
390
java/src/org/apache/log4j/chainsaw/MyTableModel.java
Normal file
390
java/src/org/apache/log4j/chainsaw/MyTableModel.java
Normal file
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.chainsaw;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import org.apache.log4j.Priority;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Represents a list of <code>EventDetails</code> objects that are sorted on
|
||||
* logging time. Methods are provided to filter the events that are visible.
|
||||
*
|
||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
||||
*/
|
||||
class MyTableModel
|
||||
extends AbstractTableModel
|
||||
{
|
||||
|
||||
/** used to log messages **/
|
||||
private static final Logger LOG = Logger.getLogger(MyTableModel.class);
|
||||
|
||||
/** use the compare logging events **/
|
||||
private static final Comparator MY_COMP = new Comparator()
|
||||
{
|
||||
/** @see Comparator **/
|
||||
public int compare(Object aObj1, Object aObj2) {
|
||||
if ((aObj1 == null) && (aObj2 == null)) {
|
||||
return 0; // treat as equal
|
||||
} else if (aObj1 == null) {
|
||||
return -1; // null less than everything
|
||||
} else if (aObj2 == null) {
|
||||
return 1; // think about it. :->
|
||||
}
|
||||
|
||||
// will assume only have LoggingEvent
|
||||
final EventDetails le1 = (EventDetails) aObj1;
|
||||
final EventDetails le2 = (EventDetails) aObj2;
|
||||
|
||||
if (le1.getTimeStamp() < le2.getTimeStamp()) {
|
||||
return 1;
|
||||
}
|
||||
// assume not two events are logged at exactly the same time
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper that actually processes incoming events.
|
||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
||||
*/
|
||||
private class Processor
|
||||
implements Runnable
|
||||
{
|
||||
/** loops getting the events **/
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
if (mPaused) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean toHead = true; // were events added to head
|
||||
boolean needUpdate = false;
|
||||
final Iterator it = mPendingEvents.iterator();
|
||||
while (it.hasNext()) {
|
||||
final EventDetails event = (EventDetails) it.next();
|
||||
mAllEvents.add(event);
|
||||
toHead = toHead && (event == mAllEvents.first());
|
||||
needUpdate = needUpdate || matchFilter(event);
|
||||
}
|
||||
mPendingEvents.clear();
|
||||
|
||||
if (needUpdate) {
|
||||
updateFilteredEvents(toHead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** names of the columns in the table **/
|
||||
private static final String[] COL_NAMES = {
|
||||
"Time", "Priority", "Trace", "Category", "NDC", "Message"};
|
||||
|
||||
/** definition of an empty list **/
|
||||
private static final EventDetails[] EMPTY_LIST = new EventDetails[] {};
|
||||
|
||||
/** used to format dates **/
|
||||
private static final DateFormat DATE_FORMATTER =
|
||||
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
|
||||
|
||||
/** the lock to control access **/
|
||||
private final Object mLock = new Object();
|
||||
/** set of all logged events - not filtered **/
|
||||
private final SortedSet mAllEvents = new TreeSet(MY_COMP);
|
||||
/** events that are visible after filtering **/
|
||||
private EventDetails[] mFilteredEvents = EMPTY_LIST;
|
||||
/** list of events that are buffered for processing **/
|
||||
private final List mPendingEvents = new ArrayList();
|
||||
/** indicates whether event collection is paused to the UI **/
|
||||
private boolean mPaused = false;
|
||||
|
||||
/** filter for the thread **/
|
||||
private String mThreadFilter = "";
|
||||
/** filter for the message **/
|
||||
private String mMessageFilter = "";
|
||||
/** filter for the NDC **/
|
||||
private String mNDCFilter = "";
|
||||
/** filter for the category **/
|
||||
private String mCategoryFilter = "";
|
||||
/** filter for the priority **/
|
||||
private Priority mPriorityFilter = Priority.DEBUG;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new <code>MyTableModel</code> instance.
|
||||
*
|
||||
*/
|
||||
MyTableModel() {
|
||||
final Thread t = new Thread(new Processor());
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Table Methods
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** @see javax.swing.table.TableModel **/
|
||||
public int getRowCount() {
|
||||
synchronized (mLock) {
|
||||
return mFilteredEvents.length;
|
||||
}
|
||||
}
|
||||
|
||||
/** @see javax.swing.table.TableModel **/
|
||||
public int getColumnCount() {
|
||||
// does not need to be synchronized
|
||||
return COL_NAMES.length;
|
||||
}
|
||||
|
||||
/** @see javax.swing.table.TableModel **/
|
||||
public String getColumnName(int aCol) {
|
||||
// does not need to be synchronized
|
||||
return COL_NAMES[aCol];
|
||||
}
|
||||
|
||||
/** @see javax.swing.table.TableModel **/
|
||||
public Class getColumnClass(int aCol) {
|
||||
// does not need to be synchronized
|
||||
return (aCol == 2) ? Boolean.class : Object.class;
|
||||
}
|
||||
|
||||
/** @see javax.swing.table.TableModel **/
|
||||
public Object getValueAt(int aRow, int aCol) {
|
||||
synchronized (mLock) {
|
||||
final EventDetails event = mFilteredEvents[aRow];
|
||||
|
||||
if (aCol == 0) {
|
||||
return DATE_FORMATTER.format(new Date(event.getTimeStamp()));
|
||||
} else if (aCol == 1) {
|
||||
return event.getPriority();
|
||||
} else if (aCol == 2) {
|
||||
return (event.getThrowableStrRep() == null)
|
||||
? Boolean.FALSE : Boolean.TRUE;
|
||||
} else if (aCol == 3) {
|
||||
return event.getCategoryName();
|
||||
} else if (aCol == 4) {
|
||||
return event.getNDC();
|
||||
}
|
||||
return event.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Public Methods
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Sets the priority to filter events on. Only events of equal or higher
|
||||
* property are now displayed.
|
||||
*
|
||||
* @param aPriority the priority to filter on
|
||||
*/
|
||||
public void setPriorityFilter(Priority aPriority) {
|
||||
synchronized (mLock) {
|
||||
mPriorityFilter = aPriority;
|
||||
updateFilteredEvents(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter for the thread field.
|
||||
*
|
||||
* @param aStr the string to match
|
||||
*/
|
||||
public void setThreadFilter(String aStr) {
|
||||
synchronized (mLock) {
|
||||
mThreadFilter = aStr.trim();
|
||||
updateFilteredEvents(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter for the message field.
|
||||
*
|
||||
* @param aStr the string to match
|
||||
*/
|
||||
public void setMessageFilter(String aStr) {
|
||||
synchronized (mLock) {
|
||||
mMessageFilter = aStr.trim();
|
||||
updateFilteredEvents(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter for the NDC field.
|
||||
*
|
||||
* @param aStr the string to match
|
||||
*/
|
||||
public void setNDCFilter(String aStr) {
|
||||
synchronized (mLock) {
|
||||
mNDCFilter = aStr.trim();
|
||||
updateFilteredEvents(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter for the category field.
|
||||
*
|
||||
* @param aStr the string to match
|
||||
*/
|
||||
public void setCategoryFilter(String aStr) {
|
||||
synchronized (mLock) {
|
||||
mCategoryFilter = aStr.trim();
|
||||
updateFilteredEvents(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an event to the list.
|
||||
*
|
||||
* @param aEvent a <code>EventDetails</code> value
|
||||
*/
|
||||
public void addEvent(EventDetails aEvent) {
|
||||
synchronized (mLock) {
|
||||
mPendingEvents.add(aEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the list of all events.
|
||||
*/
|
||||
public void clear() {
|
||||
synchronized (mLock) {
|
||||
mAllEvents.clear();
|
||||
mFilteredEvents = new EventDetails[0];
|
||||
mPendingEvents.clear();
|
||||
fireTableDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/** Toggle whether collecting events **/
|
||||
public void toggle() {
|
||||
synchronized (mLock) {
|
||||
mPaused = !mPaused;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return whether currently paused collecting events **/
|
||||
public boolean isPaused() {
|
||||
synchronized (mLock) {
|
||||
return mPaused;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the throwable information at a specified row in the filtered events.
|
||||
*
|
||||
* @param aRow the row index of the event
|
||||
* @return the throwable information
|
||||
*/
|
||||
public EventDetails getEventDetails(int aRow) {
|
||||
synchronized (mLock) {
|
||||
return mFilteredEvents[aRow];
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Private methods
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Update the filtered events data structure.
|
||||
* @param aInsertedToFront indicates whether events were added to front of
|
||||
* the events. If true, then the current first event must still exist
|
||||
* in the list after the filter is applied.
|
||||
*/
|
||||
private void updateFilteredEvents(boolean aInsertedToFront) {
|
||||
final long start = System.currentTimeMillis();
|
||||
final List filtered = new ArrayList();
|
||||
final int size = mAllEvents.size();
|
||||
final Iterator it = mAllEvents.iterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
final EventDetails event = (EventDetails) it.next();
|
||||
if (matchFilter(event)) {
|
||||
filtered.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
final EventDetails lastFirst = (mFilteredEvents.length == 0)
|
||||
? null
|
||||
: mFilteredEvents[0];
|
||||
mFilteredEvents = (EventDetails[]) filtered.toArray(EMPTY_LIST);
|
||||
|
||||
if (aInsertedToFront && (lastFirst != null)) {
|
||||
final int index = filtered.indexOf(lastFirst);
|
||||
if (index < 1) {
|
||||
LOG.warn("In strange state");
|
||||
fireTableDataChanged();
|
||||
} else {
|
||||
fireTableRowsInserted(0, index - 1);
|
||||
}
|
||||
} else {
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
||||
final long end = System.currentTimeMillis();
|
||||
LOG.debug("Total time [ms]: " + (end - start)
|
||||
+ " in update, size: " + size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an event matches the filters.
|
||||
*
|
||||
* @param aEvent the event to check for a match
|
||||
* @return whether the event matches
|
||||
*/
|
||||
private boolean matchFilter(EventDetails aEvent) {
|
||||
if (aEvent.getPriority().isGreaterOrEqual(mPriorityFilter) &&
|
||||
(aEvent.getThreadName().indexOf(mThreadFilter) >= 0) &&
|
||||
(aEvent.getCategoryName().indexOf(mCategoryFilter) >= 0) &&
|
||||
((mNDCFilter.length() == 0) ||
|
||||
((aEvent.getNDC() != null) &&
|
||||
(aEvent.getNDC().indexOf(mNDCFilter) >= 0))))
|
||||
{
|
||||
final String rm = aEvent.getMessage();
|
||||
if (rm == null) {
|
||||
// only match if we have not filtering in place
|
||||
return (mMessageFilter.length() == 0);
|
||||
} else {
|
||||
return (rm.indexOf(mMessageFilter) >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
return false; // by default not match
|
||||
}
|
||||
}
|
||||
170
java/src/org/apache/log4j/chainsaw/XMLFileHandler.java
Normal file
170
java/src/org/apache/log4j/chainsaw/XMLFileHandler.java
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.chainsaw;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
import org.apache.log4j.Level;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* A content handler for document containing Log4J events logged using the
|
||||
* XMLLayout class. It will create events and add them to a supplied model.
|
||||
*
|
||||
* @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
|
||||
* @version 1.0
|
||||
*/
|
||||
class XMLFileHandler
|
||||
extends DefaultHandler
|
||||
{
|
||||
/** represents the event tag **/
|
||||
private static final String TAG_EVENT = "log4j:event";
|
||||
/** represents the message tag **/
|
||||
private static final String TAG_MESSAGE = "log4j:message";
|
||||
/** represents the ndc tag **/
|
||||
private static final String TAG_NDC = "log4j:NDC";
|
||||
/** represents the throwable tag **/
|
||||
private static final String TAG_THROWABLE = "log4j:throwable";
|
||||
/** represents the location info tag **/
|
||||
private static final String TAG_LOCATION_INFO = "log4j:locationInfo";
|
||||
|
||||
/** where to put the events **/
|
||||
private final MyTableModel mModel;
|
||||
/** the number of events in the document **/
|
||||
private int mNumEvents;
|
||||
|
||||
/** the time of the event **/
|
||||
private long mTimeStamp;
|
||||
/** the priority (level) of the event **/
|
||||
private Level mLevel;
|
||||
/** the category of the event **/
|
||||
private String mCategoryName;
|
||||
/** the NDC for the event **/
|
||||
private String mNDC;
|
||||
/** the thread for the event **/
|
||||
private String mThreadName;
|
||||
/** the msg for the event **/
|
||||
private String mMessage;
|
||||
/** the throwable details the event **/
|
||||
private String[] mThrowableStrRep;
|
||||
/** the location details for the event **/
|
||||
private String mLocationDetails;
|
||||
/** buffer for collecting text **/
|
||||
private final StringBuffer mBuf = new StringBuffer();
|
||||
|
||||
/**
|
||||
* Creates a new <code>XMLFileHandler</code> instance.
|
||||
*
|
||||
* @param aModel where to add the events
|
||||
*/
|
||||
XMLFileHandler(MyTableModel aModel) {
|
||||
mModel = aModel;
|
||||
}
|
||||
|
||||
/** @see DefaultHandler **/
|
||||
public void startDocument()
|
||||
throws SAXException
|
||||
{
|
||||
mNumEvents = 0;
|
||||
}
|
||||
|
||||
/** @see DefaultHandler **/
|
||||
public void characters(char[] aChars, int aStart, int aLength) {
|
||||
mBuf.append(String.valueOf(aChars, aStart, aLength));
|
||||
}
|
||||
|
||||
/** @see DefaultHandler **/
|
||||
public void endElement(String aNamespaceURI,
|
||||
String aLocalName,
|
||||
String aQName)
|
||||
{
|
||||
if (TAG_EVENT.equals(aQName)) {
|
||||
addEvent();
|
||||
resetData();
|
||||
} else if (TAG_NDC.equals(aQName)) {
|
||||
mNDC = mBuf.toString();
|
||||
} else if (TAG_MESSAGE.equals(aQName)) {
|
||||
mMessage = mBuf.toString();
|
||||
} else if (TAG_THROWABLE.equals(aQName)) {
|
||||
final StringTokenizer st =
|
||||
new StringTokenizer(mBuf.toString(), "\n\t");
|
||||
mThrowableStrRep = new String[st.countTokens()];
|
||||
if (mThrowableStrRep.length > 0) {
|
||||
mThrowableStrRep[0] = st.nextToken();
|
||||
for (int i = 1; i < mThrowableStrRep.length; i++) {
|
||||
mThrowableStrRep[i] = "\t" + st.nextToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @see DefaultHandler **/
|
||||
public void startElement(String aNamespaceURI,
|
||||
String aLocalName,
|
||||
String aQName,
|
||||
Attributes aAtts)
|
||||
{
|
||||
mBuf.setLength(0);
|
||||
|
||||
if (TAG_EVENT.equals(aQName)) {
|
||||
mThreadName = aAtts.getValue("thread");
|
||||
mTimeStamp = Long.parseLong(aAtts.getValue("timestamp"));
|
||||
mCategoryName = aAtts.getValue("logger");
|
||||
mLevel = Level.toLevel(aAtts.getValue("level"));
|
||||
} else if (TAG_LOCATION_INFO.equals(aQName)) {
|
||||
mLocationDetails = aAtts.getValue("class") + "."
|
||||
+ aAtts.getValue("method")
|
||||
+ "(" + aAtts.getValue("file") + ":" + aAtts.getValue("line")
|
||||
+ ")";
|
||||
}
|
||||
}
|
||||
|
||||
/** @return the number of events in the document **/
|
||||
int getNumEvents() {
|
||||
return mNumEvents;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Private methods
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** Add an event to the model **/
|
||||
private void addEvent() {
|
||||
mModel.addEvent(new EventDetails(mTimeStamp,
|
||||
mLevel,
|
||||
mCategoryName,
|
||||
mNDC,
|
||||
mThreadName,
|
||||
mMessage,
|
||||
mThrowableStrRep,
|
||||
mLocationDetails));
|
||||
mNumEvents++;
|
||||
}
|
||||
|
||||
/** Reset the data for an event **/
|
||||
private void resetData() {
|
||||
mTimeStamp = 0;
|
||||
mLevel = null;
|
||||
mCategoryName = null;
|
||||
mNDC = null;
|
||||
mThreadName = null;
|
||||
mMessage = null;
|
||||
mThrowableStrRep = null;
|
||||
mLocationDetails = null;
|
||||
}
|
||||
}
|
||||
BIN
java/src/org/apache/log4j/chainsaw/doc-files/screen_01.png
Normal file
BIN
java/src/org/apache/log4j/chainsaw/doc-files/screen_01.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
118
java/src/org/apache/log4j/chainsaw/package.html
Normal file
118
java/src/org/apache/log4j/chainsaw/package.html
Normal file
@@ -0,0 +1,118 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You 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.
|
||||
|
||||
-->
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Chainsaw Tool</TITLE>
|
||||
</head>
|
||||
|
||||
<BODY>
|
||||
|
||||
<P>Chainsaw is a GUI log viewer and filter for the log4j
|
||||
package. By default it listens for <a
|
||||
href="../spi/LoggingEvent.html">LoggingEvent</A> objects sent using
|
||||
the <A href="../net/SocketAppender.html">SocketAppender</A> and
|
||||
displays them in a table. The events can be filtered based on:</P>
|
||||
|
||||
<UL>
|
||||
<LI>Level </li>
|
||||
|
||||
<LI>Thread name</li>
|
||||
|
||||
<LI>Logger</li>
|
||||
<LI>Message</li>
|
||||
|
||||
<LI>NDC</LI>
|
||||
</UL>
|
||||
|
||||
<P>All the details for each event can be displayed by selecting
|
||||
the event in the table.</P>
|
||||
|
||||
<P>Chainsaw also supports loading a events logged to a file using
|
||||
the <A href="../xml/XMLLayout.html">XMLLayout</A> format. This
|
||||
is great for analysing log files, and means you do not need to
|
||||
keep Chainsaw running continously. It is easy to add support
|
||||
for loading events from other sources like JDBC.</P>
|
||||
|
||||
<P>A picture is worth a thousand words: </P>
|
||||
|
||||
<P align=center><A
|
||||
href="doc-files/screen_01.png"><IMG
|
||||
height="50%" alt="Screen shot of chainsaw"
|
||||
src="doc-files/screen_01.png"
|
||||
width="50%"></A>.</P>
|
||||
|
||||
<P>Finally, why is it called chainsaw?
|
||||
Because it cuts your log (file) down to size. :-)
|
||||
</P>
|
||||
|
||||
|
||||
<H2>Requirements</H2>
|
||||
|
||||
<P>Chainsaw is based on the Swing API which requires JDK 1.2 or later.</P>
|
||||
|
||||
|
||||
<H2>Running chainsaw</H2>
|
||||
|
||||
<H3>Setup</H3>
|
||||
<P>You need to include the <code>log4j.jar</code> in the classpath.
|
||||
|
||||
<H3>Usage</H3>
|
||||
|
||||
<P>The command line usage is:</P>
|
||||
|
||||
<PRE> java -D<property>=<value> org.apache.log4j.chainsaw.Main </PRE>
|
||||
|
||||
<P>The default behaviour of chainsaw can be changed by setting system properties
|
||||
using the <CODE>-D<property>=<value></CODE> arguments to java. The
|
||||
following table describes what properties can be set:</P>
|
||||
|
||||
<TABLE cellSpacing=0 cellPadding=2 border=1>
|
||||
|
||||
<TR>
|
||||
<TD vAlign=top><B>Property</B></TD>
|
||||
<TD vAlign=top><B>Description</B></TD></TR>
|
||||
<TR>
|
||||
<TD vAlign=top>chainsaw.port</TD>
|
||||
<TD vAlign=top>Indicates which port to listen for connections on. Defaults
|
||||
to <SPAN class=default>"4445"</SPAN>.
|
||||
</TD>
|
||||
</TR>
|
||||
</TBODY>
|
||||
</TABLE>
|
||||
|
||||
<H2>Configuring Log4J</H2>
|
||||
|
||||
<P>You will need to configure log4j to send logging events to
|
||||
Chainsaw. Here is a sample <CODE>log4j.properties</CODE> file
|
||||
for sending logging events to Chainsaw.</P>
|
||||
|
||||
<PRE>
|
||||
log4j.rootLogger=DEBUG, CHAINSAW_CLIENT
|
||||
|
||||
log4j.appender.CHAINSAW_CLIENT=org.apache.log4j.net.SocketAppender
|
||||
log4j.appender.CHAINSAW_CLIENT.RemoteHost=localhost
|
||||
log4j.appender.CHAINSAW_CLIENT.Port=4445
|
||||
log4j.appender.CHAINSAW_CLIENT.LocationInfo=true
|
||||
</PRE>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
108
java/src/org/apache/log4j/config/PropertyGetter.java
Normal file
108
java/src/org/apache/log4j/config/PropertyGetter.java
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.config;
|
||||
|
||||
import org.apache.log4j.Priority;
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
/**
|
||||
Used for inferring configuration information for a log4j's component.
|
||||
|
||||
@author Anders Kristensen
|
||||
*/
|
||||
public class PropertyGetter {
|
||||
protected static final Object[] NULL_ARG = new Object[] {};
|
||||
protected Object obj;
|
||||
protected PropertyDescriptor[] props;
|
||||
|
||||
public interface PropertyCallback {
|
||||
void foundProperty(Object obj, String prefix, String name, Object value);
|
||||
}
|
||||
|
||||
/**
|
||||
Create a new PropertyGetter for the specified Object. This is done
|
||||
in prepartion for invoking {@link
|
||||
#getProperties(PropertyGetter.PropertyCallback, String)} one or
|
||||
more times.
|
||||
|
||||
@param obj the object for which to set properties */
|
||||
public
|
||||
PropertyGetter(Object obj) throws IntrospectionException {
|
||||
BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
|
||||
props = bi.getPropertyDescriptors();
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
public
|
||||
static
|
||||
void getProperties(Object obj, PropertyCallback callback, String prefix) {
|
||||
try {
|
||||
new PropertyGetter(obj).getProperties(callback, prefix);
|
||||
} catch (IntrospectionException ex) {
|
||||
LogLog.error("Failed to introspect object " + obj, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
void getProperties(PropertyCallback callback, String prefix) {
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Method getter = props[i].getReadMethod();
|
||||
if (getter == null) continue;
|
||||
if (!isHandledType(getter.getReturnType())) {
|
||||
//System.err.println("Ignoring " + props[i].getName() +" " + getter.getReturnType());
|
||||
continue;
|
||||
}
|
||||
String name = props[i].getName();
|
||||
try {
|
||||
Object result = getter.invoke(obj, NULL_ARG);
|
||||
//System.err.println("PROP " + name +": " + result);
|
||||
if (result != null) {
|
||||
callback.foundProperty(obj, prefix, name, result);
|
||||
}
|
||||
} catch (IllegalAccessException ex) {
|
||||
LogLog.warn("Failed to get value of property " + name);
|
||||
} catch (InvocationTargetException ex) {
|
||||
if (ex.getTargetException() instanceof InterruptedException
|
||||
|| ex.getTargetException() instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
LogLog.warn("Failed to get value of property " + name);
|
||||
} catch (RuntimeException ex) {
|
||||
LogLog.warn("Failed to get value of property " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected
|
||||
boolean isHandledType(Class type) {
|
||||
return String.class.isAssignableFrom(type) ||
|
||||
Integer.TYPE.isAssignableFrom(type) ||
|
||||
Long.TYPE.isAssignableFrom(type) ||
|
||||
Boolean.TYPE.isAssignableFrom(type) ||
|
||||
Priority.class.isAssignableFrom(type);
|
||||
}
|
||||
}
|
||||
168
java/src/org/apache/log4j/config/PropertyPrinter.java
Normal file
168
java/src/org/apache/log4j/config/PropertyPrinter.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.config;
|
||||
|
||||
import org.apache.log4j.Appender;
|
||||
import org.apache.log4j.Category;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.LogManager;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
Prints the configuration of the log4j default hierarchy
|
||||
(which needs to be auto-initialized) as a propoperties file
|
||||
on a {@link PrintWriter}.
|
||||
|
||||
@author Anders Kristensen
|
||||
*/
|
||||
public class PropertyPrinter implements PropertyGetter.PropertyCallback {
|
||||
protected int numAppenders = 0;
|
||||
protected Hashtable appenderNames = new Hashtable();
|
||||
protected Hashtable layoutNames = new Hashtable();
|
||||
protected PrintWriter out;
|
||||
protected boolean doCapitalize;
|
||||
|
||||
public
|
||||
PropertyPrinter(PrintWriter out) {
|
||||
this(out, false);
|
||||
}
|
||||
|
||||
public
|
||||
PropertyPrinter(PrintWriter out, boolean doCapitalize) {
|
||||
this.out = out;
|
||||
this.doCapitalize = doCapitalize;
|
||||
|
||||
print(out);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
protected
|
||||
String genAppName() {
|
||||
return "A" + numAppenders++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified appender name is considered to have
|
||||
* been generated, that is, if it is of the form A[0-9]+.
|
||||
*/
|
||||
protected
|
||||
boolean isGenAppName(String name) {
|
||||
if (name.length() < 2 || name.charAt(0) != 'A') return false;
|
||||
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
if (name.charAt(i) < '0' || name.charAt(i) > '9') return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the configuration of the default log4j hierarchy as a Java
|
||||
* properties file on the specified Writer.
|
||||
*
|
||||
* <p>N.B. print() can be invoked only once!
|
||||
*/
|
||||
public
|
||||
void print(PrintWriter out) {
|
||||
printOptions(out, Logger.getRootLogger());
|
||||
|
||||
Enumeration cats = LogManager.getCurrentLoggers();
|
||||
while (cats.hasMoreElements()) {
|
||||
printOptions(out, (Logger) cats.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.2.15
|
||||
*/
|
||||
protected
|
||||
void printOptions(PrintWriter out, Category cat) {
|
||||
Enumeration appenders = cat.getAllAppenders();
|
||||
Level prio = cat.getLevel();
|
||||
String appenderString = (prio == null ? "" : prio.toString());
|
||||
|
||||
while (appenders.hasMoreElements()) {
|
||||
Appender app = (Appender) appenders.nextElement();
|
||||
String name;
|
||||
|
||||
if ((name = (String) appenderNames.get(app)) == null) {
|
||||
|
||||
// first assign name to the appender
|
||||
if ((name = app.getName()) == null || isGenAppName(name)) {
|
||||
name = genAppName();
|
||||
}
|
||||
appenderNames.put(app, name);
|
||||
|
||||
printOptions(out, app, "log4j.appender."+name);
|
||||
if (app.getLayout() != null) {
|
||||
printOptions(out, app.getLayout(), "log4j.appender."+name+".layout");
|
||||
}
|
||||
}
|
||||
appenderString += ", " + name;
|
||||
}
|
||||
String catKey = (cat == Logger.getRootLogger())
|
||||
? "log4j.rootLogger"
|
||||
: "log4j.logger." + cat.getName();
|
||||
if (appenderString != "") {
|
||||
out.println(catKey + "=" + appenderString);
|
||||
}
|
||||
if (!cat.getAdditivity() && cat != Logger.getRootLogger()) {
|
||||
out.println("log4j.additivity." + cat.getName() + "=false");
|
||||
}
|
||||
}
|
||||
|
||||
protected void printOptions(PrintWriter out, Logger cat) {
|
||||
printOptions(out, (Category) cat);
|
||||
}
|
||||
|
||||
protected
|
||||
void printOptions(PrintWriter out, Object obj, String fullname) {
|
||||
out.println(fullname + "=" + obj.getClass().getName());
|
||||
PropertyGetter.getProperties(obj, this, fullname + ".");
|
||||
}
|
||||
|
||||
public void foundProperty(Object obj, String prefix, String name, Object value) {
|
||||
// XXX: Properties encode value.toString()
|
||||
if (obj instanceof Appender && "name".equals(name)) {
|
||||
return;
|
||||
}
|
||||
if (doCapitalize) {
|
||||
name = capitalize(name);
|
||||
}
|
||||
out.println(prefix + name + "=" + value.toString());
|
||||
}
|
||||
|
||||
public static String capitalize(String name) {
|
||||
if (Character.isLowerCase(name.charAt(0))) {
|
||||
if (name.length() == 1 || Character.isLowerCase(name.charAt(1))) {
|
||||
StringBuffer newname = new StringBuffer(name);
|
||||
newname.setCharAt(0, Character.toUpperCase(name.charAt(0)));
|
||||
return newname.toString();
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
// for testing
|
||||
public static void main(String[] args) {
|
||||
new PropertyPrinter(new PrintWriter(System.out));
|
||||
}
|
||||
}
|
||||
310
java/src/org/apache/log4j/config/PropertySetter.java
Normal file
310
java/src/org/apache/log4j/config/PropertySetter.java
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
// Contributors: Georg Lundesgaard
|
||||
|
||||
package org.apache.log4j.config;
|
||||
|
||||
import org.apache.log4j.Appender;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Priority;
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
import org.apache.log4j.helpers.OptionConverter;
|
||||
import org.apache.log4j.spi.OptionHandler;
|
||||
import org.apache.log4j.spi.ErrorHandler;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
General purpose Object property setter. Clients repeatedly invokes
|
||||
{@link #setProperty setProperty(name,value)} in order to invoke setters
|
||||
on the Object specified in the constructor. This class relies on the
|
||||
JavaBeans {@link Introspector} to analyze the given Object Class using
|
||||
reflection.
|
||||
|
||||
<p>Usage:
|
||||
<pre>
|
||||
PropertySetter ps = new PropertySetter(anObject);
|
||||
ps.set("name", "Joe");
|
||||
ps.set("age", "32");
|
||||
ps.set("isMale", "true");
|
||||
</pre>
|
||||
will cause the invocations anObject.setName("Joe"), anObject.setAge(32),
|
||||
and setMale(true) if such methods exist with those signatures.
|
||||
Otherwise an {@link IntrospectionException} are thrown.
|
||||
|
||||
@author Anders Kristensen
|
||||
@since 1.1
|
||||
*/
|
||||
public class PropertySetter {
|
||||
protected Object obj;
|
||||
protected PropertyDescriptor[] props;
|
||||
|
||||
/**
|
||||
Create a new PropertySetter for the specified Object. This is done
|
||||
in prepartion for invoking {@link #setProperty} one or more times.
|
||||
|
||||
@param obj the object for which to set properties
|
||||
*/
|
||||
public
|
||||
PropertySetter(Object obj) {
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
/**
|
||||
Uses JavaBeans {@link Introspector} to computer setters of object to be
|
||||
configured.
|
||||
*/
|
||||
protected
|
||||
void introspect() {
|
||||
try {
|
||||
BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
|
||||
props = bi.getPropertyDescriptors();
|
||||
} catch (IntrospectionException ex) {
|
||||
LogLog.error("Failed to introspect "+obj+": " + ex.getMessage());
|
||||
props = new PropertyDescriptor[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the properties of an object passed as a parameter in one
|
||||
go. The <code>properties</code> are parsed relative to a
|
||||
<code>prefix</code>.
|
||||
|
||||
@param obj The object to configure.
|
||||
@param properties A java.util.Properties containing keys and values.
|
||||
@param prefix Only keys having the specified prefix will be set.
|
||||
*/
|
||||
public
|
||||
static
|
||||
void setProperties(Object obj, Properties properties, String prefix) {
|
||||
new PropertySetter(obj).setProperties(properties, prefix);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Set the properites for the object that match the
|
||||
<code>prefix</code> passed as parameter.
|
||||
|
||||
|
||||
*/
|
||||
public
|
||||
void setProperties(Properties properties, String prefix) {
|
||||
int len = prefix.length();
|
||||
|
||||
for (Enumeration e = properties.propertyNames(); e.hasMoreElements(); ) {
|
||||
String key = (String) e.nextElement();
|
||||
|
||||
// handle only properties that start with the desired frefix.
|
||||
if (key.startsWith(prefix)) {
|
||||
|
||||
|
||||
// ignore key if it contains dots after the prefix
|
||||
if (key.indexOf('.', len + 1) > 0) {
|
||||
//System.err.println("----------Ignoring---["+key
|
||||
// +"], prefix=["+prefix+"].");
|
||||
continue;
|
||||
}
|
||||
|
||||
String value = OptionConverter.findAndSubst(key, properties);
|
||||
key = key.substring(len);
|
||||
if (("layout".equals(key) || "errorhandler".equals(key)) && obj instanceof Appender) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// if the property type is an OptionHandler
|
||||
// (for example, triggeringPolicy of org.apache.log4j.rolling.RollingFileAppender)
|
||||
PropertyDescriptor prop = getPropertyDescriptor(Introspector.decapitalize(key));
|
||||
if (prop != null
|
||||
&& OptionHandler.class.isAssignableFrom(prop.getPropertyType())
|
||||
&& prop.getWriteMethod() != null) {
|
||||
OptionHandler opt = (OptionHandler)
|
||||
OptionConverter.instantiateByKey(properties, prefix + key,
|
||||
prop.getPropertyType(),
|
||||
null);
|
||||
PropertySetter setter = new PropertySetter(opt);
|
||||
setter.setProperties(properties, prefix + key + ".");
|
||||
try {
|
||||
prop.getWriteMethod().invoke(this.obj, new Object[] { opt });
|
||||
} catch(IllegalAccessException ex) {
|
||||
LogLog.warn("Failed to set property [" + key +
|
||||
"] to value \"" + value + "\". ", ex);
|
||||
} catch(InvocationTargetException ex) {
|
||||
if (ex.getTargetException() instanceof InterruptedException
|
||||
|| ex.getTargetException() instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
LogLog.warn("Failed to set property [" + key +
|
||||
"] to value \"" + value + "\". ", ex);
|
||||
} catch(RuntimeException ex) {
|
||||
LogLog.warn("Failed to set property [" + key +
|
||||
"] to value \"" + value + "\". ", ex);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
setProperty(key, value);
|
||||
}
|
||||
}
|
||||
activate();
|
||||
}
|
||||
|
||||
/**
|
||||
Set a property on this PropertySetter's Object. If successful, this
|
||||
method will invoke a setter method on the underlying Object. The
|
||||
setter is the one for the specified property name and the value is
|
||||
determined partly from the setter argument type and partly from the
|
||||
value specified in the call to this method.
|
||||
|
||||
<p>If the setter expects a String no conversion is necessary.
|
||||
If it expects an int, then an attempt is made to convert 'value'
|
||||
to an int using new Integer(value). If the setter expects a boolean,
|
||||
the conversion is by new Boolean(value).
|
||||
|
||||
@param name name of the property
|
||||
@param value String value of the property
|
||||
*/
|
||||
public
|
||||
void setProperty(String name, String value) {
|
||||
if (value == null) return;
|
||||
|
||||
name = Introspector.decapitalize(name);
|
||||
PropertyDescriptor prop = getPropertyDescriptor(name);
|
||||
|
||||
//LogLog.debug("---------Key: "+name+", type="+prop.getPropertyType());
|
||||
|
||||
if (prop == null) {
|
||||
LogLog.warn("No such property [" + name + "] in "+
|
||||
obj.getClass().getName()+"." );
|
||||
} else {
|
||||
try {
|
||||
setProperty(prop, name, value);
|
||||
} catch (PropertySetterException ex) {
|
||||
LogLog.warn("Failed to set property [" + name +
|
||||
"] to value \"" + value + "\". ", ex.rootCause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Set the named property given a {@link PropertyDescriptor}.
|
||||
|
||||
@param prop A PropertyDescriptor describing the characteristics
|
||||
of the property to set.
|
||||
@param name The named of the property to set.
|
||||
@param value The value of the property.
|
||||
*/
|
||||
public
|
||||
void setProperty(PropertyDescriptor prop, String name, String value)
|
||||
throws PropertySetterException {
|
||||
Method setter = prop.getWriteMethod();
|
||||
if (setter == null) {
|
||||
throw new PropertySetterException("No setter for property ["+name+"].");
|
||||
}
|
||||
Class[] paramTypes = setter.getParameterTypes();
|
||||
if (paramTypes.length != 1) {
|
||||
throw new PropertySetterException("#params for setter != 1");
|
||||
}
|
||||
|
||||
Object arg;
|
||||
try {
|
||||
arg = convertArg(value, paramTypes[0]);
|
||||
} catch (Throwable t) {
|
||||
throw new PropertySetterException("Conversion to type ["+paramTypes[0]+
|
||||
"] failed. Reason: "+t);
|
||||
}
|
||||
if (arg == null) {
|
||||
throw new PropertySetterException(
|
||||
"Conversion to type ["+paramTypes[0]+"] failed.");
|
||||
}
|
||||
LogLog.debug("Setting property [" + name + "] to [" +arg+"].");
|
||||
try {
|
||||
setter.invoke(obj, new Object[] { arg });
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new PropertySetterException(ex);
|
||||
} catch (InvocationTargetException ex) {
|
||||
if (ex.getTargetException() instanceof InterruptedException
|
||||
|| ex.getTargetException() instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
throw new PropertySetterException(ex);
|
||||
} catch (RuntimeException ex) {
|
||||
throw new PropertySetterException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convert <code>val</code> a String parameter to an object of a
|
||||
given type.
|
||||
*/
|
||||
protected
|
||||
Object convertArg(String val, Class type) {
|
||||
if(val == null)
|
||||
return null;
|
||||
|
||||
String v = val.trim();
|
||||
if (String.class.isAssignableFrom(type)) {
|
||||
return val;
|
||||
} else if (Integer.TYPE.isAssignableFrom(type)) {
|
||||
return new Integer(v);
|
||||
} else if (Long.TYPE.isAssignableFrom(type)) {
|
||||
return new Long(v);
|
||||
} else if (Boolean.TYPE.isAssignableFrom(type)) {
|
||||
if ("true".equalsIgnoreCase(v)) {
|
||||
return Boolean.TRUE;
|
||||
} else if ("false".equalsIgnoreCase(v)) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
} else if (Priority.class.isAssignableFrom(type)) {
|
||||
return OptionConverter.toLevel(v, (Level) Level.DEBUG);
|
||||
} else if (ErrorHandler.class.isAssignableFrom(type)) {
|
||||
return OptionConverter.instantiateByClassName(v,
|
||||
ErrorHandler.class, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected
|
||||
PropertyDescriptor getPropertyDescriptor(String name) {
|
||||
if (props == null) introspect();
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
if (name.equals(props[i].getName())) {
|
||||
return props[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public
|
||||
void activate() {
|
||||
if (obj instanceof OptionHandler) {
|
||||
((OptionHandler) obj).activateOptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.config;
|
||||
|
||||
/**
|
||||
* Thrown when an error is encountered whilst attempting to set a property
|
||||
* using the {@link PropertySetter} utility class.
|
||||
*
|
||||
* @author Anders Kristensen
|
||||
* @since 1.1
|
||||
*/
|
||||
public class PropertySetterException extends Exception {
|
||||
private static final long serialVersionUID = -1352613734254235861L;
|
||||
protected Throwable rootCause;
|
||||
|
||||
public
|
||||
PropertySetterException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public
|
||||
PropertySetterException(Throwable rootCause)
|
||||
{
|
||||
super();
|
||||
this.rootCause = rootCause;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns descriptive text on the cause of this exception.
|
||||
*/
|
||||
public
|
||||
String getMessage() {
|
||||
String msg = super.getMessage();
|
||||
if (msg == null && rootCause != null) {
|
||||
msg = rootCause.getMessage();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
23
java/src/org/apache/log4j/config/package.html
Normal file
23
java/src/org/apache/log4j/config/package.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<html>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You 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.
|
||||
|
||||
-->
|
||||
|
||||
<body>
|
||||
Package used in getting/setting component properties.
|
||||
</body>
|
||||
</html>
|
||||
145
java/src/org/apache/log4j/helpers/AbsoluteTimeDateFormat.java
Normal file
145
java/src/org/apache/log4j/helpers/AbsoluteTimeDateFormat.java
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.ParsePosition;
|
||||
import java.text.DateFormat;
|
||||
|
||||
|
||||
/**
|
||||
Formats a {@link Date} in the format "HH:mm:ss,SSS" for example,
|
||||
"15:49:37,459".
|
||||
|
||||
@author Ceki Gülcü
|
||||
@author Andrew Vajoczki
|
||||
|
||||
@since 0.7.5
|
||||
*/
|
||||
public class AbsoluteTimeDateFormat extends DateFormat {
|
||||
private static final long serialVersionUID = -388856345976723342L;
|
||||
|
||||
/**
|
||||
String constant used to specify {@link
|
||||
org.apache.log4j.helpers.AbsoluteTimeDateFormat} in layouts. Current
|
||||
value is <b>ABSOLUTE</b>. */
|
||||
public final static String ABS_TIME_DATE_FORMAT = "ABSOLUTE";
|
||||
|
||||
/**
|
||||
String constant used to specify {@link
|
||||
org.apache.log4j.helpers.DateTimeDateFormat} in layouts. Current
|
||||
value is <b>DATE</b>.
|
||||
*/
|
||||
public final static String DATE_AND_TIME_DATE_FORMAT = "DATE";
|
||||
|
||||
/**
|
||||
String constant used to specify {@link
|
||||
org.apache.log4j.helpers.ISO8601DateFormat} in layouts. Current
|
||||
value is <b>ISO8601</b>.
|
||||
*/
|
||||
public final static String ISO8601_DATE_FORMAT = "ISO8601";
|
||||
|
||||
public
|
||||
AbsoluteTimeDateFormat() {
|
||||
setCalendar(Calendar.getInstance());
|
||||
}
|
||||
|
||||
public
|
||||
AbsoluteTimeDateFormat(TimeZone timeZone) {
|
||||
setCalendar(Calendar.getInstance(timeZone));
|
||||
}
|
||||
|
||||
private static long previousTime;
|
||||
private static char[] previousTimeWithoutMillis = new char[9]; // "HH:mm:ss."
|
||||
|
||||
/**
|
||||
Appends to <code>sbuf</code> the time in the format
|
||||
"HH:mm:ss,SSS" for example, "15:49:37,459"
|
||||
|
||||
@param date the date to format
|
||||
@param sbuf the string buffer to write to
|
||||
@param fieldPosition remains untouched
|
||||
*/
|
||||
public
|
||||
StringBuffer format(Date date, StringBuffer sbuf,
|
||||
FieldPosition fieldPosition) {
|
||||
|
||||
long now = date.getTime();
|
||||
int millis = (int)(now % 1000);
|
||||
|
||||
if ((now - millis) != previousTime || previousTimeWithoutMillis[0] == 0) {
|
||||
// We reach this point at most once per second
|
||||
// across all threads instead of each time format()
|
||||
// is called. This saves considerable CPU time.
|
||||
|
||||
calendar.setTime(date);
|
||||
|
||||
int start = sbuf.length();
|
||||
|
||||
int hour = calendar.get(Calendar.HOUR_OF_DAY);
|
||||
if(hour < 10) {
|
||||
sbuf.append('0');
|
||||
}
|
||||
sbuf.append(hour);
|
||||
sbuf.append(':');
|
||||
|
||||
int mins = calendar.get(Calendar.MINUTE);
|
||||
if(mins < 10) {
|
||||
sbuf.append('0');
|
||||
}
|
||||
sbuf.append(mins);
|
||||
sbuf.append(':');
|
||||
|
||||
int secs = calendar.get(Calendar.SECOND);
|
||||
if(secs < 10) {
|
||||
sbuf.append('0');
|
||||
}
|
||||
sbuf.append(secs);
|
||||
sbuf.append(',');
|
||||
|
||||
// store the time string for next time to avoid recomputation
|
||||
sbuf.getChars(start, sbuf.length(), previousTimeWithoutMillis, 0);
|
||||
|
||||
previousTime = now - millis;
|
||||
}
|
||||
else {
|
||||
sbuf.append(previousTimeWithoutMillis);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(millis < 100)
|
||||
sbuf.append('0');
|
||||
if(millis < 10)
|
||||
sbuf.append('0');
|
||||
|
||||
sbuf.append(millis);
|
||||
return sbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
This method does not do anything but return <code>null</code>.
|
||||
*/
|
||||
public
|
||||
Date parse(String s, ParsePosition pos) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
176
java/src/org/apache/log4j/helpers/AppenderAttachableImpl.java
Normal file
176
java/src/org/apache/log4j/helpers/AppenderAttachableImpl.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import org.apache.log4j.spi.AppenderAttachable;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
import org.apache.log4j.Appender;
|
||||
import java.util.Vector;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
A straightforward implementation of the {@link AppenderAttachable}
|
||||
interface.
|
||||
|
||||
@author Ceki Gülcü
|
||||
@since version 0.9.1 */
|
||||
public class AppenderAttachableImpl implements AppenderAttachable {
|
||||
|
||||
/** Array of appenders. */
|
||||
protected Vector appenderList;
|
||||
|
||||
/**
|
||||
Attach an appender. If the appender is already in the list in
|
||||
won't be added again.
|
||||
*/
|
||||
public
|
||||
void addAppender(Appender newAppender) {
|
||||
// Null values for newAppender parameter are strictly forbidden.
|
||||
if(newAppender == null)
|
||||
return;
|
||||
|
||||
if(appenderList == null) {
|
||||
appenderList = new Vector(1);
|
||||
}
|
||||
if(!appenderList.contains(newAppender))
|
||||
appenderList.addElement(newAppender);
|
||||
}
|
||||
|
||||
/**
|
||||
Call the <code>doAppend</code> method on all attached appenders. */
|
||||
public
|
||||
int appendLoopOnAppenders(LoggingEvent event) {
|
||||
int size = 0;
|
||||
Appender appender;
|
||||
|
||||
if(appenderList != null) {
|
||||
size = appenderList.size();
|
||||
for(int i = 0; i < size; i++) {
|
||||
appender = (Appender) appenderList.elementAt(i);
|
||||
appender.doAppend(event);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get all attached appenders as an Enumeration. If there are no
|
||||
attached appenders <code>null</code> is returned.
|
||||
|
||||
@return Enumeration An enumeration of attached appenders.
|
||||
*/
|
||||
public
|
||||
Enumeration getAllAppenders() {
|
||||
if(appenderList == null)
|
||||
return null;
|
||||
else
|
||||
return appenderList.elements();
|
||||
}
|
||||
|
||||
/**
|
||||
Look for an attached appender named as <code>name</code>.
|
||||
|
||||
<p>Return the appender with that name if in the list. Return null
|
||||
otherwise.
|
||||
|
||||
*/
|
||||
public
|
||||
Appender getAppender(String name) {
|
||||
if(appenderList == null || name == null)
|
||||
return null;
|
||||
|
||||
int size = appenderList.size();
|
||||
Appender appender;
|
||||
for(int i = 0; i < size; i++) {
|
||||
appender = (Appender) appenderList.elementAt(i);
|
||||
if(name.equals(appender.getName()))
|
||||
return appender;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns <code>true</code> if the specified appender is in the
|
||||
list of attached appenders, <code>false</code> otherwise.
|
||||
|
||||
@since 1.2 */
|
||||
public
|
||||
boolean isAttached(Appender appender) {
|
||||
if(appenderList == null || appender == null)
|
||||
return false;
|
||||
|
||||
int size = appenderList.size();
|
||||
Appender a;
|
||||
for(int i = 0; i < size; i++) {
|
||||
a = (Appender) appenderList.elementAt(i);
|
||||
if(a == appender)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Remove and close all previously attached appenders.
|
||||
* */
|
||||
public
|
||||
void removeAllAppenders() {
|
||||
if(appenderList != null) {
|
||||
int len = appenderList.size();
|
||||
for(int i = 0; i < len; i++) {
|
||||
Appender a = (Appender) appenderList.elementAt(i);
|
||||
a.close();
|
||||
}
|
||||
appenderList.removeAllElements();
|
||||
appenderList = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Remove the appender passed as parameter form the list of attached
|
||||
appenders. */
|
||||
public
|
||||
void removeAppender(Appender appender) {
|
||||
if(appender == null || appenderList == null)
|
||||
return;
|
||||
appenderList.removeElement(appender);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Remove the appender with the name passed as parameter form the
|
||||
list of appenders.
|
||||
*/
|
||||
public
|
||||
void removeAppender(String name) {
|
||||
if(name == null || appenderList == null) return;
|
||||
int size = appenderList.size();
|
||||
for(int i = 0; i < size; i++) {
|
||||
if(name.equals(((Appender)appenderList.elementAt(i)).getName())) {
|
||||
appenderList.removeElementAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
181
java/src/org/apache/log4j/helpers/BoundedFIFO.java
Normal file
181
java/src/org/apache/log4j/helpers/BoundedFIFO.java
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
// Contributors: Mathias Bogaert
|
||||
// joelr@viair.com
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
<code>BoundedFIFO</code> serves as the bounded first-in-first-out
|
||||
buffer heavily used by the {@link org.apache.log4j.AsyncAppender}.
|
||||
|
||||
@author Ceki Gülcü
|
||||
@since version 0.9.1 */
|
||||
public class BoundedFIFO {
|
||||
|
||||
LoggingEvent[] buf;
|
||||
int numElements = 0;
|
||||
int first = 0;
|
||||
int next = 0;
|
||||
int maxSize;
|
||||
|
||||
/**
|
||||
Instantiate a new BoundedFIFO with a maximum size passed as argument.
|
||||
*/
|
||||
public
|
||||
BoundedFIFO(int maxSize) {
|
||||
if(maxSize < 1) {
|
||||
throw new IllegalArgumentException("The maxSize argument ("+maxSize+
|
||||
") is not a positive integer.");
|
||||
}
|
||||
this.maxSize = maxSize;
|
||||
buf = new LoggingEvent[maxSize];
|
||||
}
|
||||
|
||||
/**
|
||||
Get the first element in the buffer. Returns <code>null</code> if
|
||||
there are no elements in the buffer. */
|
||||
public
|
||||
LoggingEvent get() {
|
||||
if(numElements == 0)
|
||||
return null;
|
||||
|
||||
LoggingEvent r = buf[first];
|
||||
buf[first] = null; // help garbage collection
|
||||
|
||||
if(++first == maxSize) {
|
||||
first = 0;
|
||||
}
|
||||
numElements--;
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
Place a {@link LoggingEvent} in the buffer. If the buffer is full
|
||||
then the event is <b>silently dropped</b>. It is the caller's
|
||||
responsability to make sure that the buffer has free space. */
|
||||
public
|
||||
void put(LoggingEvent o) {
|
||||
if(numElements != maxSize) {
|
||||
buf[next] = o;
|
||||
if(++next == maxSize) {
|
||||
next = 0;
|
||||
}
|
||||
numElements++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Get the maximum size of the buffer.
|
||||
*/
|
||||
public
|
||||
int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
Return <code>true</code> if the buffer is full, that is, whether
|
||||
the number of elements in the buffer equals the buffer size. */
|
||||
public
|
||||
boolean isFull() {
|
||||
return numElements == maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the number of elements in the buffer. This number is
|
||||
guaranteed to be in the range 0 to <code>maxSize</code>
|
||||
(inclusive).
|
||||
*/
|
||||
public
|
||||
int length() {
|
||||
return numElements;
|
||||
}
|
||||
|
||||
|
||||
int min(int a, int b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Resize the buffer to a new size. If the new size is smaller than
|
||||
the old size events might be lost.
|
||||
|
||||
@since 1.1
|
||||
*/
|
||||
synchronized
|
||||
public
|
||||
void resize(int newSize) {
|
||||
if(newSize == maxSize)
|
||||
return;
|
||||
|
||||
|
||||
LoggingEvent[] tmp = new LoggingEvent[newSize];
|
||||
|
||||
// we should not copy beyond the buf array
|
||||
int len1 = maxSize - first;
|
||||
|
||||
// we should not copy beyond the tmp array
|
||||
len1 = min(len1, newSize);
|
||||
|
||||
// er.. how much do we actually need to copy?
|
||||
// We should not copy more than the actual number of elements.
|
||||
len1 = min(len1, numElements);
|
||||
|
||||
// Copy from buf starting a first, to tmp, starting at position 0, len1 elements.
|
||||
System.arraycopy(buf, first, tmp, 0, len1);
|
||||
|
||||
// Are there any uncopied elements and is there still space in the new array?
|
||||
int len2 = 0;
|
||||
if((len1 < numElements) && (len1 < newSize)) {
|
||||
len2 = numElements - len1;
|
||||
len2 = min(len2, newSize - len1);
|
||||
System.arraycopy(buf, 0, tmp, len1, len2);
|
||||
}
|
||||
|
||||
this.buf = tmp;
|
||||
this.maxSize = newSize;
|
||||
this.first=0;
|
||||
this.numElements = len1+len2;
|
||||
this.next = this.numElements;
|
||||
if(this.next == this.maxSize) // this should never happen, but again, it just might.
|
||||
this.next = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns <code>true</code> if there is just one element in the
|
||||
buffer. In other words, if there were no elements before the last
|
||||
{@link #put} operation completed. */
|
||||
public
|
||||
boolean wasEmpty() {
|
||||
return numElements == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns <code>true</code> if the number of elements in the
|
||||
buffer plus 1 equals the maximum buffer size, returns
|
||||
<code>false</code> otherwise. */
|
||||
public
|
||||
boolean wasFull() {
|
||||
return (numElements+1 == maxSize);
|
||||
}
|
||||
|
||||
}
|
||||
63
java/src/org/apache/log4j/helpers/CountingQuietWriter.java
Normal file
63
java/src/org/apache/log4j/helpers/CountingQuietWriter.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.log4j.spi.ErrorHandler;
|
||||
import org.apache.log4j.spi.ErrorCode;
|
||||
|
||||
/**
|
||||
Counts the number of bytes written.
|
||||
|
||||
@author Heinz Richter, heinz.richter@frogdot.com
|
||||
@since 0.8.1
|
||||
|
||||
*/
|
||||
public class CountingQuietWriter extends QuietWriter {
|
||||
|
||||
protected long count;
|
||||
|
||||
public
|
||||
CountingQuietWriter(Writer writer, ErrorHandler eh) {
|
||||
super(writer, eh);
|
||||
}
|
||||
|
||||
public
|
||||
void write(String string) {
|
||||
try {
|
||||
out.write(string);
|
||||
count += string.length();
|
||||
}
|
||||
catch(IOException e) {
|
||||
errorHandler.error("Write failure.", e, ErrorCode.WRITE_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public
|
||||
void setCount(long count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
}
|
||||
159
java/src/org/apache/log4j/helpers/CyclicBuffer.java
Normal file
159
java/src/org/apache/log4j/helpers/CyclicBuffer.java
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
|
||||
CyclicBuffer is used by other appenders to hold {@link LoggingEvent
|
||||
LoggingEvents} for immediate or differed display.
|
||||
|
||||
<p>This buffer gives read access to any element in the buffer not
|
||||
just the first or last element.
|
||||
|
||||
@author Ceki Gülcü
|
||||
@since 0.9.0
|
||||
|
||||
*/
|
||||
public class CyclicBuffer {
|
||||
|
||||
LoggingEvent[] ea;
|
||||
int first;
|
||||
int last;
|
||||
int numElems;
|
||||
int maxSize;
|
||||
|
||||
/**
|
||||
Instantiate a new CyclicBuffer of at most <code>maxSize</code> events.
|
||||
|
||||
The <code>maxSize</code> argument must a positive integer.
|
||||
|
||||
@param maxSize The maximum number of elements in the buffer.
|
||||
*/
|
||||
public CyclicBuffer(int maxSize) throws IllegalArgumentException {
|
||||
if(maxSize < 1) {
|
||||
throw new IllegalArgumentException("The maxSize argument ("+maxSize+
|
||||
") is not a positive integer.");
|
||||
}
|
||||
this.maxSize = maxSize;
|
||||
ea = new LoggingEvent[maxSize];
|
||||
first = 0;
|
||||
last = 0;
|
||||
numElems = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Add an <code>event</code> as the last event in the buffer.
|
||||
|
||||
*/
|
||||
public
|
||||
void add(LoggingEvent event) {
|
||||
ea[last] = event;
|
||||
if(++last == maxSize)
|
||||
last = 0;
|
||||
|
||||
if(numElems < maxSize)
|
||||
numElems++;
|
||||
else if(++first == maxSize)
|
||||
first = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the <i>i</i>th oldest event currently in the buffer. If
|
||||
<em>i</em> is outside the range 0 to the number of elements
|
||||
currently in the buffer, then <code>null</code> is returned.
|
||||
|
||||
|
||||
*/
|
||||
public
|
||||
LoggingEvent get(int i) {
|
||||
if(i < 0 || i >= numElems)
|
||||
return null;
|
||||
|
||||
return ea[(first + i) % maxSize];
|
||||
}
|
||||
|
||||
public
|
||||
int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the oldest (first) element in the buffer. The oldest element
|
||||
is removed from the buffer.
|
||||
*/
|
||||
public
|
||||
LoggingEvent get() {
|
||||
LoggingEvent r = null;
|
||||
if(numElems > 0) {
|
||||
numElems--;
|
||||
r = ea[first];
|
||||
ea[first] = null;
|
||||
if(++first == maxSize)
|
||||
first = 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the number of elements in the buffer. This number is
|
||||
guaranteed to be in the range 0 to <code>maxSize</code>
|
||||
(inclusive).
|
||||
*/
|
||||
public
|
||||
int length() {
|
||||
return numElems;
|
||||
}
|
||||
|
||||
/**
|
||||
Resize the cyclic buffer to <code>newSize</code>.
|
||||
|
||||
@throws IllegalArgumentException if <code>newSize</code> is negative.
|
||||
*/
|
||||
public
|
||||
void resize(int newSize) {
|
||||
if(newSize < 0) {
|
||||
throw new IllegalArgumentException("Negative array size ["+newSize+
|
||||
"] not allowed.");
|
||||
}
|
||||
if(newSize == numElems)
|
||||
return; // nothing to do
|
||||
|
||||
LoggingEvent[] temp = new LoggingEvent[newSize];
|
||||
|
||||
int loopLen = newSize < numElems ? newSize : numElems;
|
||||
|
||||
for(int i = 0; i < loopLen; i++) {
|
||||
temp[i] = ea[first];
|
||||
ea[first] = null;
|
||||
if(++first == numElems)
|
||||
first = 0;
|
||||
}
|
||||
ea = temp;
|
||||
first = 0;
|
||||
numElems = loopLen;
|
||||
maxSize = newSize;
|
||||
if (loopLen == newSize) {
|
||||
last = 0;
|
||||
} else {
|
||||
last = loopLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
200
java/src/org/apache/log4j/helpers/DateLayout.java
Normal file
200
java/src/org/apache/log4j/helpers/DateLayout.java
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import org.apache.log4j.Layout;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import java.text.FieldPosition;
|
||||
|
||||
|
||||
/**
|
||||
This abstract layout takes care of all the date related options and
|
||||
formatting work.
|
||||
|
||||
|
||||
@author Ceki Gülcü
|
||||
*/
|
||||
abstract public class DateLayout extends Layout {
|
||||
|
||||
/**
|
||||
String constant designating no time information. Current value of
|
||||
this constant is <b>NULL</b>.
|
||||
|
||||
*/
|
||||
public final static String NULL_DATE_FORMAT = "NULL";
|
||||
|
||||
/**
|
||||
String constant designating relative time. Current value of
|
||||
this constant is <b>RELATIVE</b>.
|
||||
*/
|
||||
public final static String RELATIVE_TIME_DATE_FORMAT = "RELATIVE";
|
||||
|
||||
protected FieldPosition pos = new FieldPosition(0);
|
||||
|
||||
/**
|
||||
@deprecated Options are now handled using the JavaBeans paradigm.
|
||||
This constant is not longer needed and will be removed in the
|
||||
<em>near</em> term.
|
||||
*/
|
||||
final static public String DATE_FORMAT_OPTION = "DateFormat";
|
||||
|
||||
/**
|
||||
@deprecated Options are now handled using the JavaBeans paradigm.
|
||||
This constant is not longer needed and will be removed in the
|
||||
<em>near</em> term.
|
||||
*/
|
||||
final static public String TIMEZONE_OPTION = "TimeZone";
|
||||
|
||||
private String timeZoneID;
|
||||
private String dateFormatOption;
|
||||
|
||||
protected DateFormat dateFormat;
|
||||
protected Date date = new Date();
|
||||
|
||||
/**
|
||||
@deprecated Use the setter method for the option directly instead
|
||||
of the generic <code>setOption</code> method.
|
||||
*/
|
||||
public
|
||||
String[] getOptionStrings() {
|
||||
return new String[] {DATE_FORMAT_OPTION, TIMEZONE_OPTION};
|
||||
}
|
||||
|
||||
/**
|
||||
@deprecated Use the setter method for the option directly instead
|
||||
of the generic <code>setOption</code> method.
|
||||
*/
|
||||
public
|
||||
void setOption(String option, String value) {
|
||||
if(option.equalsIgnoreCase(DATE_FORMAT_OPTION)) {
|
||||
dateFormatOption = value.toUpperCase();
|
||||
} else if(option.equalsIgnoreCase(TIMEZONE_OPTION)) {
|
||||
timeZoneID = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The value of the <b>DateFormat</b> option should be either an
|
||||
argument to the constructor of {@link SimpleDateFormat} or one of
|
||||
the srings "NULL", "RELATIVE", "ABSOLUTE", "DATE" or "ISO8601.
|
||||
*/
|
||||
public
|
||||
void setDateFormat(String dateFormat) {
|
||||
if (dateFormat != null) {
|
||||
dateFormatOption = dateFormat;
|
||||
}
|
||||
setDateFormat(dateFormatOption, TimeZone.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
Returns value of the <b>DateFormat</b> option.
|
||||
*/
|
||||
public
|
||||
String getDateFormat() {
|
||||
return dateFormatOption;
|
||||
}
|
||||
|
||||
/**
|
||||
The <b>TimeZoneID</b> option is a time zone ID string in the format
|
||||
expected by the {@link TimeZone#getTimeZone} method.
|
||||
*/
|
||||
public
|
||||
void setTimeZone(String timeZone) {
|
||||
this.timeZoneID = timeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns value of the <b>TimeZone</b> option.
|
||||
*/
|
||||
public
|
||||
String getTimeZone() {
|
||||
return timeZoneID;
|
||||
}
|
||||
|
||||
public
|
||||
void activateOptions() {
|
||||
setDateFormat(dateFormatOption);
|
||||
if(timeZoneID != null && dateFormat != null) {
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(timeZoneID));
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
void dateFormat(StringBuffer buf, LoggingEvent event) {
|
||||
if(dateFormat != null) {
|
||||
date.setTime(event.timeStamp);
|
||||
dateFormat.format(date, buf, this.pos);
|
||||
buf.append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the {@link DateFormat} used to format time and date in the
|
||||
zone determined by <code>timeZone</code>.
|
||||
*/
|
||||
public
|
||||
void setDateFormat(DateFormat dateFormat, TimeZone timeZone) {
|
||||
this.dateFormat = dateFormat;
|
||||
this.dateFormat.setTimeZone(timeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the DateFormat used to format date and time in the time zone
|
||||
determined by <code>timeZone</code> parameter. The {@link DateFormat} used
|
||||
will depend on the <code>dateFormatType</code>.
|
||||
|
||||
<p>The recognized types are {@link #NULL_DATE_FORMAT}, {@link
|
||||
#RELATIVE_TIME_DATE_FORMAT} {@link
|
||||
AbsoluteTimeDateFormat#ABS_TIME_DATE_FORMAT}, {@link
|
||||
AbsoluteTimeDateFormat#DATE_AND_TIME_DATE_FORMAT} and {@link
|
||||
AbsoluteTimeDateFormat#ISO8601_DATE_FORMAT}. If the
|
||||
<code>dateFormatType</code> is not one of the above, then the
|
||||
argument is assumed to be a date pattern for {@link
|
||||
SimpleDateFormat}.
|
||||
*/
|
||||
public
|
||||
void setDateFormat(String dateFormatType, TimeZone timeZone) {
|
||||
if(dateFormatType == null) {
|
||||
this.dateFormat = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if(dateFormatType.equalsIgnoreCase(NULL_DATE_FORMAT)) {
|
||||
this.dateFormat = null;
|
||||
} else if (dateFormatType.equalsIgnoreCase(RELATIVE_TIME_DATE_FORMAT)) {
|
||||
this.dateFormat = new RelativeTimeDateFormat();
|
||||
} else if(dateFormatType.equalsIgnoreCase(
|
||||
AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT)) {
|
||||
this.dateFormat = new AbsoluteTimeDateFormat(timeZone);
|
||||
} else if(dateFormatType.equalsIgnoreCase(
|
||||
AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT)) {
|
||||
this.dateFormat = new DateTimeDateFormat(timeZone);
|
||||
} else if(dateFormatType.equalsIgnoreCase(
|
||||
AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT)) {
|
||||
this.dateFormat = new ISO8601DateFormat(timeZone);
|
||||
} else {
|
||||
this.dateFormat = new SimpleDateFormat(dateFormatType);
|
||||
this.dateFormat.setTimeZone(timeZone);
|
||||
}
|
||||
}
|
||||
}
|
||||
85
java/src/org/apache/log4j/helpers/DateTimeDateFormat.java
Normal file
85
java/src/org/apache/log4j/helpers/DateTimeDateFormat.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Date;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.ParsePosition;
|
||||
import java.text.DateFormatSymbols;
|
||||
|
||||
/**
|
||||
Formats a {@link Date} in the format "dd MMM yyyy HH:mm:ss,SSS" for example,
|
||||
"06 Nov 1994 15:49:37,459".
|
||||
|
||||
@author Ceki Gülcü
|
||||
@since 0.7.5
|
||||
*/
|
||||
public class DateTimeDateFormat extends AbsoluteTimeDateFormat {
|
||||
private static final long serialVersionUID = 5547637772208514971L;
|
||||
|
||||
String[] shortMonths;
|
||||
|
||||
public
|
||||
DateTimeDateFormat() {
|
||||
super();
|
||||
shortMonths = new DateFormatSymbols().getShortMonths();
|
||||
}
|
||||
|
||||
public
|
||||
DateTimeDateFormat(TimeZone timeZone) {
|
||||
this();
|
||||
setCalendar(Calendar.getInstance(timeZone));
|
||||
}
|
||||
|
||||
/**
|
||||
Appends to <code>sbuf</code> the date in the format "dd MMM yyyy
|
||||
HH:mm:ss,SSS" for example, "06 Nov 1994 08:49:37,459".
|
||||
|
||||
@param sbuf the string buffer to write to
|
||||
*/
|
||||
public
|
||||
StringBuffer format(Date date, StringBuffer sbuf,
|
||||
FieldPosition fieldPosition) {
|
||||
|
||||
calendar.setTime(date);
|
||||
|
||||
int day = calendar.get(Calendar.DAY_OF_MONTH);
|
||||
if(day < 10)
|
||||
sbuf.append('0');
|
||||
sbuf.append(day);
|
||||
sbuf.append(' ');
|
||||
sbuf.append(shortMonths[calendar.get(Calendar.MONTH)]);
|
||||
sbuf.append(' ');
|
||||
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
sbuf.append(year);
|
||||
sbuf.append(' ');
|
||||
|
||||
return super.format(date, sbuf, fieldPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
This method does not do anything but return <code>null</code>.
|
||||
*/
|
||||
public
|
||||
Date parse(java.lang.String s, ParsePosition pos) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
111
java/src/org/apache/log4j/helpers/FileWatchdog.java
Normal file
111
java/src/org/apache/log4j/helpers/FileWatchdog.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
// Contributors: Mathias Bogaert
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
Check every now and then that a certain file has not changed. If it
|
||||
has, then call the {@link #doOnChange} method.
|
||||
|
||||
|
||||
@author Ceki Gülcü
|
||||
@since version 0.9.1 */
|
||||
public abstract class FileWatchdog extends Thread {
|
||||
|
||||
/**
|
||||
The default delay between every file modification check, set to 60
|
||||
seconds. */
|
||||
static final public long DEFAULT_DELAY = 60000;
|
||||
/**
|
||||
The name of the file to observe for changes.
|
||||
*/
|
||||
protected String filename;
|
||||
|
||||
/**
|
||||
The delay to observe between every check. By default set {@link
|
||||
#DEFAULT_DELAY}. */
|
||||
protected long delay = DEFAULT_DELAY;
|
||||
|
||||
File file;
|
||||
long lastModif = 0;
|
||||
boolean warnedAlready = false;
|
||||
boolean interrupted = false;
|
||||
|
||||
protected
|
||||
FileWatchdog(String filename) {
|
||||
super("FileWatchdog");
|
||||
this.filename = filename;
|
||||
file = new File(filename);
|
||||
setDaemon(true);
|
||||
checkAndConfigure();
|
||||
}
|
||||
|
||||
/**
|
||||
Set the delay to observe between each check of the file changes.
|
||||
*/
|
||||
public
|
||||
void setDelay(long delay) {
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
abstract
|
||||
protected
|
||||
void doOnChange();
|
||||
|
||||
protected
|
||||
void checkAndConfigure() {
|
||||
boolean fileExists;
|
||||
try {
|
||||
fileExists = file.exists();
|
||||
} catch(SecurityException e) {
|
||||
LogLog.warn("Was not allowed to read check file existance, file:["+
|
||||
filename+"].");
|
||||
interrupted = true; // there is no point in continuing
|
||||
return;
|
||||
}
|
||||
|
||||
if(fileExists) {
|
||||
long l = file.lastModified(); // this can also throw a SecurityException
|
||||
if(l > lastModif) { // however, if we reached this point this
|
||||
lastModif = l; // is very unlikely.
|
||||
doOnChange();
|
||||
warnedAlready = false;
|
||||
}
|
||||
} else {
|
||||
if(!warnedAlready) {
|
||||
LogLog.debug("["+filename+"] does not exist.");
|
||||
warnedAlready = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
void run() {
|
||||
while(!interrupted) {
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
} catch(InterruptedException e) {
|
||||
// no interruption expected
|
||||
}
|
||||
checkAndConfigure();
|
||||
}
|
||||
}
|
||||
}
|
||||
45
java/src/org/apache/log4j/helpers/FormattingInfo.java
Normal file
45
java/src/org/apache/log4j/helpers/FormattingInfo.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
|
||||
/**
|
||||
FormattingInfo instances contain the information obtained when parsing
|
||||
formatting modifiers in conversion modifiers.
|
||||
|
||||
@author <a href=mailto:jim_cakalic@na.biomerieux.com>Jim Cakalic</a>
|
||||
@author Ceki Gülcü
|
||||
|
||||
@since 0.8.2
|
||||
*/
|
||||
public class FormattingInfo {
|
||||
int min = -1;
|
||||
int max = 0x7FFFFFFF;
|
||||
boolean leftAlign = false;
|
||||
|
||||
void reset() {
|
||||
min = -1;
|
||||
max = 0x7FFFFFFF;
|
||||
leftAlign = false;
|
||||
}
|
||||
|
||||
void dump() {
|
||||
LogLog.debug("min="+min+", max="+max+", leftAlign="+leftAlign);
|
||||
}
|
||||
}
|
||||
|
||||
155
java/src/org/apache/log4j/helpers/ISO8601DateFormat.java
Normal file
155
java/src/org/apache/log4j/helpers/ISO8601DateFormat.java
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Date;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.ParsePosition;
|
||||
|
||||
// Contributors: Arndt Schoenewald <arndt@ibm23093i821.mc.schoenewald.de>
|
||||
|
||||
/**
|
||||
Formats a {@link Date} in the format "yyyy-MM-dd HH:mm:ss,SSS" for example
|
||||
"1999-11-27 15:49:37,459".
|
||||
|
||||
<p>Refer to the <a
|
||||
href=http://www.cl.cam.ac.uk/~mgk25/iso-time.html>summary of the
|
||||
International Standard Date and Time Notation</a> for more
|
||||
information on this format.
|
||||
|
||||
@author Ceki Gülcü
|
||||
@author Andrew Vajoczki
|
||||
|
||||
@since 0.7.5
|
||||
*/
|
||||
public class ISO8601DateFormat extends AbsoluteTimeDateFormat {
|
||||
private static final long serialVersionUID = -759840745298755296L;
|
||||
|
||||
public
|
||||
ISO8601DateFormat() {
|
||||
}
|
||||
|
||||
public
|
||||
ISO8601DateFormat(TimeZone timeZone) {
|
||||
super(timeZone);
|
||||
}
|
||||
|
||||
static private long lastTime;
|
||||
static private char[] lastTimeString = new char[20];
|
||||
|
||||
/**
|
||||
Appends a date in the format "YYYY-mm-dd HH:mm:ss,SSS"
|
||||
to <code>sbuf</code>. For example: "1999-11-27 15:49:37,459".
|
||||
|
||||
@param sbuf the <code>StringBuffer</code> to write to
|
||||
*/
|
||||
public
|
||||
StringBuffer format(Date date, StringBuffer sbuf,
|
||||
FieldPosition fieldPosition) {
|
||||
|
||||
long now = date.getTime();
|
||||
int millis = (int)(now % 1000);
|
||||
|
||||
if ((now - millis) != lastTime || lastTimeString[0] == 0) {
|
||||
// We reach this point at most once per second
|
||||
// across all threads instead of each time format()
|
||||
// is called. This saves considerable CPU time.
|
||||
|
||||
calendar.setTime(date);
|
||||
|
||||
int start = sbuf.length();
|
||||
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
sbuf.append(year);
|
||||
|
||||
String month;
|
||||
switch(calendar.get(Calendar.MONTH)) {
|
||||
case Calendar.JANUARY: month = "-01-"; break;
|
||||
case Calendar.FEBRUARY: month = "-02-"; break;
|
||||
case Calendar.MARCH: month = "-03-"; break;
|
||||
case Calendar.APRIL: month = "-04-"; break;
|
||||
case Calendar.MAY: month = "-05-"; break;
|
||||
case Calendar.JUNE: month = "-06-"; break;
|
||||
case Calendar.JULY: month = "-07-"; break;
|
||||
case Calendar.AUGUST: month = "-08-"; break;
|
||||
case Calendar.SEPTEMBER: month = "-09-"; break;
|
||||
case Calendar.OCTOBER: month = "-10-"; break;
|
||||
case Calendar.NOVEMBER: month = "-11-"; break;
|
||||
case Calendar.DECEMBER: month = "-12-"; break;
|
||||
default: month = "-NA-"; break;
|
||||
}
|
||||
sbuf.append(month);
|
||||
|
||||
int day = calendar.get(Calendar.DAY_OF_MONTH);
|
||||
if(day < 10)
|
||||
sbuf.append('0');
|
||||
sbuf.append(day);
|
||||
|
||||
sbuf.append(' ');
|
||||
|
||||
int hour = calendar.get(Calendar.HOUR_OF_DAY);
|
||||
if(hour < 10) {
|
||||
sbuf.append('0');
|
||||
}
|
||||
sbuf.append(hour);
|
||||
sbuf.append(':');
|
||||
|
||||
int mins = calendar.get(Calendar.MINUTE);
|
||||
if(mins < 10) {
|
||||
sbuf.append('0');
|
||||
}
|
||||
sbuf.append(mins);
|
||||
sbuf.append(':');
|
||||
|
||||
int secs = calendar.get(Calendar.SECOND);
|
||||
if(secs < 10) {
|
||||
sbuf.append('0');
|
||||
}
|
||||
sbuf.append(secs);
|
||||
|
||||
sbuf.append(',');
|
||||
|
||||
// store the time string for next time to avoid recomputation
|
||||
sbuf.getChars(start, sbuf.length(), lastTimeString, 0);
|
||||
lastTime = now - millis;
|
||||
}
|
||||
else {
|
||||
sbuf.append(lastTimeString);
|
||||
}
|
||||
|
||||
|
||||
if (millis < 100)
|
||||
sbuf.append('0');
|
||||
if (millis < 10)
|
||||
sbuf.append('0');
|
||||
|
||||
sbuf.append(millis);
|
||||
return sbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
This method does not do anything but return <code>null</code>.
|
||||
*/
|
||||
public
|
||||
Date parse(java.lang.String s, ParsePosition pos) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
200
java/src/org/apache/log4j/helpers/Loader.java
Normal file
200
java/src/org/apache/log4j/helpers/Loader.java
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import java.net.URL;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
|
||||
/**
|
||||
Load resources (or images) from various sources.
|
||||
|
||||
@author Ceki Gülcü
|
||||
*/
|
||||
|
||||
public class Loader {
|
||||
|
||||
static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";
|
||||
|
||||
// We conservatively assume that we are running under Java 1.x
|
||||
static private boolean java1 = true;
|
||||
|
||||
static private boolean ignoreTCL = false;
|
||||
|
||||
static {
|
||||
String prop = OptionConverter.getSystemProperty("java.version", null);
|
||||
|
||||
if(prop != null) {
|
||||
int i = prop.indexOf('.');
|
||||
if(i != -1) {
|
||||
if(prop.charAt(i+1) != '1')
|
||||
java1 = false;
|
||||
}
|
||||
}
|
||||
String ignoreTCLProp = OptionConverter.getSystemProperty("log4j.ignoreTCL", null);
|
||||
if(ignoreTCLProp != null) {
|
||||
ignoreTCL = OptionConverter.toBoolean(ignoreTCLProp, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a resource by delegating to getResource(String).
|
||||
* @param resource resource name
|
||||
* @param clazz class, ignored.
|
||||
* @return URL to resource or null.
|
||||
* @deprecated as of 1.2.
|
||||
*/
|
||||
public static URL getResource(String resource, Class clazz) {
|
||||
return getResource(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
This method will search for <code>resource</code> in different
|
||||
places. The search order is as follows:
|
||||
|
||||
<ol>
|
||||
|
||||
<p><li>Search for <code>resource</code> using the thread context
|
||||
class loader under Java2. If that fails, search for
|
||||
<code>resource</code> using the class loader that loaded this
|
||||
class (<code>Loader</code>). Under JDK 1.1, only the the class
|
||||
loader that loaded this class (<code>Loader</code>) is used.
|
||||
|
||||
<p><li>Try one last time with
|
||||
<code>ClassLoader.getSystemResource(resource)</code>, that is is
|
||||
using the system class loader in JDK 1.2 and virtual machine's
|
||||
built-in class loader in JDK 1.1.
|
||||
|
||||
</ol>
|
||||
*/
|
||||
static public URL getResource(String resource) {
|
||||
ClassLoader classLoader = null;
|
||||
URL url = null;
|
||||
|
||||
try {
|
||||
if(!java1 && !ignoreTCL) {
|
||||
classLoader = getTCL();
|
||||
if(classLoader != null) {
|
||||
LogLog.debug("Trying to find ["+resource+"] using context classloader "
|
||||
+classLoader+".");
|
||||
url = classLoader.getResource(resource);
|
||||
if(url != null) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We could not find resource. Ler us now try with the
|
||||
// classloader that loaded this class.
|
||||
classLoader = Loader.class.getClassLoader();
|
||||
if(classLoader != null) {
|
||||
LogLog.debug("Trying to find ["+resource+"] using "+classLoader
|
||||
+" class loader.");
|
||||
url = classLoader.getResource(resource);
|
||||
if(url != null) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
} catch(IllegalAccessException t) {
|
||||
LogLog.warn(TSTR, t);
|
||||
} catch(InvocationTargetException t) {
|
||||
if (t.getTargetException() instanceof InterruptedException
|
||||
|| t.getTargetException() instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
LogLog.warn(TSTR, t);
|
||||
} catch(Throwable t) {
|
||||
//
|
||||
// can't be InterruptedException or InterruptedIOException
|
||||
// since not declared, must be error or RuntimeError.
|
||||
LogLog.warn(TSTR, t);
|
||||
}
|
||||
|
||||
// Last ditch attempt: get the resource from the class path. It
|
||||
// may be the case that clazz was loaded by the Extentsion class
|
||||
// loader which the parent of the system class loader. Hence the
|
||||
// code below.
|
||||
LogLog.debug("Trying to find ["+resource+
|
||||
"] using ClassLoader.getSystemResource().");
|
||||
return ClassLoader.getSystemResource(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
Are we running under JDK 1.x?
|
||||
*/
|
||||
public
|
||||
static
|
||||
boolean isJava1() {
|
||||
return java1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Thread Context Loader which is a JDK 1.2 feature. If we
|
||||
* are running under JDK 1.1 or anything else goes wrong the method
|
||||
* returns <code>null<code>.
|
||||
*
|
||||
* */
|
||||
private static ClassLoader getTCL() throws IllegalAccessException,
|
||||
InvocationTargetException {
|
||||
|
||||
// Are we running on a JDK 1.2 or later system?
|
||||
Method method = null;
|
||||
try {
|
||||
method = Thread.class.getMethod("getContextClassLoader", null);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// We are running on JDK 1.1
|
||||
return null;
|
||||
}
|
||||
|
||||
return (ClassLoader) method.invoke(Thread.currentThread(), null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* If running under JDK 1.2 load the specified class using the
|
||||
* <code>Thread</code> <code>contextClassLoader</code> if that
|
||||
* fails try Class.forname. Under JDK 1.1 only Class.forName is
|
||||
* used.
|
||||
*
|
||||
*/
|
||||
static public Class loadClass (String clazz) throws ClassNotFoundException {
|
||||
// Just call Class.forName(clazz) if we are running under JDK 1.1
|
||||
// or if we are instructed to ignore the TCL.
|
||||
if(java1 || ignoreTCL) {
|
||||
return Class.forName(clazz);
|
||||
} else {
|
||||
try {
|
||||
return getTCL().loadClass(clazz);
|
||||
}
|
||||
// we reached here because tcl was null or because of a
|
||||
// security exception, or because clazz could not be loaded...
|
||||
// In any case we now try one more time
|
||||
catch(InvocationTargetException e) {
|
||||
if (e.getTargetException() instanceof InterruptedException
|
||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
} catch(Throwable t) {
|
||||
}
|
||||
}
|
||||
return Class.forName(clazz);
|
||||
}
|
||||
}
|
||||
189
java/src/org/apache/log4j/helpers/LogLog.java
Normal file
189
java/src/org/apache/log4j/helpers/LogLog.java
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
/**
|
||||
This class used to output log statements from within the log4j package.
|
||||
|
||||
<p>Log4j components cannot make log4j logging calls. However, it is
|
||||
sometimes useful for the user to learn about what log4j is
|
||||
doing. You can enable log4j internal logging by defining the
|
||||
<b>log4j.configDebug</b> variable.
|
||||
|
||||
<p>All log4j internal debug calls go to <code>System.out</code>
|
||||
where as internal error messages are sent to
|
||||
<code>System.err</code>. All internal messages are prepended with
|
||||
the string "log4j: ".
|
||||
|
||||
@since 0.8.2
|
||||
@author Ceki Gülcü
|
||||
*/
|
||||
public class LogLog {
|
||||
|
||||
/**
|
||||
Defining this value makes log4j print log4j-internal debug
|
||||
statements to <code>System.out</code>.
|
||||
|
||||
<p> The value of this string is <b>log4j.debug</b>.
|
||||
|
||||
<p>Note that the search for all option names is case sensitive. */
|
||||
public static final String DEBUG_KEY="log4j.debug";
|
||||
|
||||
|
||||
/**
|
||||
Defining this value makes log4j components print log4j-internal
|
||||
debug statements to <code>System.out</code>.
|
||||
|
||||
<p> The value of this string is <b>log4j.configDebug</b>.
|
||||
|
||||
<p>Note that the search for all option names is case sensitive.
|
||||
|
||||
@deprecated Use {@link #DEBUG_KEY} instead.
|
||||
*/
|
||||
public static final String CONFIG_DEBUG_KEY="log4j.configDebug";
|
||||
|
||||
protected static boolean debugEnabled = false;
|
||||
|
||||
/**
|
||||
In quietMode not even errors generate any output.
|
||||
*/
|
||||
private static boolean quietMode = false;
|
||||
|
||||
private static final String PREFIX = "log4j: ";
|
||||
private static final String ERR_PREFIX = "log4j:ERROR ";
|
||||
private static final String WARN_PREFIX = "log4j:WARN ";
|
||||
|
||||
static {
|
||||
String key = OptionConverter.getSystemProperty(DEBUG_KEY, null);
|
||||
|
||||
if(key == null) {
|
||||
key = OptionConverter.getSystemProperty(CONFIG_DEBUG_KEY, null);
|
||||
}
|
||||
|
||||
if(key != null) {
|
||||
debugEnabled = OptionConverter.toBoolean(key, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Allows to enable/disable log4j internal logging.
|
||||
*/
|
||||
static
|
||||
public
|
||||
void setInternalDebugging(boolean enabled) {
|
||||
debugEnabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
This method is used to output log4j internal debug
|
||||
statements. Output goes to <code>System.out</code>.
|
||||
*/
|
||||
public
|
||||
static
|
||||
void debug(String msg) {
|
||||
if(debugEnabled && !quietMode) {
|
||||
System.out.println(PREFIX+msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
This method is used to output log4j internal debug
|
||||
statements. Output goes to <code>System.out</code>.
|
||||
*/
|
||||
public
|
||||
static
|
||||
void debug(String msg, Throwable t) {
|
||||
if(debugEnabled && !quietMode) {
|
||||
System.out.println(PREFIX+msg);
|
||||
if(t != null)
|
||||
t.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This method is used to output log4j internal error
|
||||
statements. There is no way to disable error statements.
|
||||
Output goes to <code>System.err</code>.
|
||||
*/
|
||||
public
|
||||
static
|
||||
void error(String msg) {
|
||||
if(quietMode)
|
||||
return;
|
||||
System.err.println(ERR_PREFIX+msg);
|
||||
}
|
||||
|
||||
/**
|
||||
This method is used to output log4j internal error
|
||||
statements. There is no way to disable error statements.
|
||||
Output goes to <code>System.err</code>.
|
||||
*/
|
||||
public
|
||||
static
|
||||
void error(String msg, Throwable t) {
|
||||
if(quietMode)
|
||||
return;
|
||||
|
||||
System.err.println(ERR_PREFIX+msg);
|
||||
if(t != null) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
In quite mode no LogLog generates strictly no output, not even
|
||||
for errors.
|
||||
|
||||
@param quietMode A true for not
|
||||
*/
|
||||
public
|
||||
static
|
||||
void setQuietMode(boolean quietMode) {
|
||||
LogLog.quietMode = quietMode;
|
||||
}
|
||||
|
||||
/**
|
||||
This method is used to output log4j internal warning
|
||||
statements. There is no way to disable warning statements.
|
||||
Output goes to <code>System.err</code>. */
|
||||
public
|
||||
static
|
||||
void warn(String msg) {
|
||||
if(quietMode)
|
||||
return;
|
||||
|
||||
System.err.println(WARN_PREFIX+msg);
|
||||
}
|
||||
|
||||
/**
|
||||
This method is used to output log4j internal warnings. There is
|
||||
no way to disable warning statements. Output goes to
|
||||
<code>System.err</code>. */
|
||||
public
|
||||
static
|
||||
void warn(String msg, Throwable t) {
|
||||
if(quietMode)
|
||||
return;
|
||||
|
||||
System.err.println(WARN_PREFIX+msg);
|
||||
if(t != null) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
92
java/src/org/apache/log4j/helpers/MDCKeySetExtractor.java
Normal file
92
java/src/org/apache/log4j/helpers/MDCKeySetExtractor.java
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
import org.apache.log4j.pattern.LogEvent;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Set;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
|
||||
|
||||
public final class MDCKeySetExtractor {
|
||||
private final Method getKeySetMethod;
|
||||
public static final MDCKeySetExtractor INSTANCE =
|
||||
new MDCKeySetExtractor();
|
||||
|
||||
|
||||
private MDCKeySetExtractor() {
|
||||
//
|
||||
// log4j 1.2.15 and later will have method to get names
|
||||
// of all keys in MDC
|
||||
//
|
||||
Method getMethod = null;
|
||||
|
||||
try {
|
||||
getMethod = LoggingEvent.class.getMethod(
|
||||
"getPropertyKeySet", null);
|
||||
} catch(Exception ex) {
|
||||
getMethod = null;
|
||||
}
|
||||
getKeySetMethod = getMethod;
|
||||
|
||||
}
|
||||
|
||||
public Set getPropertyKeySet(final LoggingEvent event) throws Exception {
|
||||
//
|
||||
// MDC keys are not visible prior to log4j 1.2.15
|
||||
//
|
||||
Set keySet = null;
|
||||
if (getKeySetMethod != null) {
|
||||
keySet = (Set) getKeySetMethod.invoke(event, null);
|
||||
} else {
|
||||
//
|
||||
// for 1.2.14 and earlier could serialize and
|
||||
// extract MDC content
|
||||
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
|
||||
ObjectOutputStream os = new ObjectOutputStream(outBytes);
|
||||
os.writeObject(event);
|
||||
os.close();
|
||||
|
||||
byte[] raw = outBytes.toByteArray();
|
||||
//
|
||||
// bytes 6 and 7 should be the length of the original classname
|
||||
// should be the same as our substitute class name
|
||||
final String subClassName = LogEvent.class.getName();
|
||||
if (raw[6] == 0 || raw[7] == subClassName.length()) {
|
||||
//
|
||||
// manipulate stream to use our class name
|
||||
//
|
||||
for (int i = 0; i < subClassName.length(); i++) {
|
||||
raw[8 + i] = (byte) subClassName.charAt(i);
|
||||
}
|
||||
ByteArrayInputStream inBytes = new ByteArrayInputStream(raw);
|
||||
ObjectInputStream is = new ObjectInputStream(inBytes);
|
||||
Object cracked = is.readObject();
|
||||
if (cracked instanceof LogEvent) {
|
||||
keySet = ((LogEvent) cracked).getPropertyKeySet();
|
||||
}
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
return keySet;
|
||||
}
|
||||
}
|
||||
50
java/src/org/apache/log4j/helpers/NullEnumeration.java
Normal file
50
java/src/org/apache/log4j/helpers/NullEnumeration.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
|
||||
An always-empty Enumerator.
|
||||
|
||||
@author Anders Kristensen
|
||||
@since version 1.0
|
||||
*/
|
||||
public class NullEnumeration implements Enumeration {
|
||||
private static final NullEnumeration instance = new NullEnumeration();
|
||||
|
||||
private
|
||||
NullEnumeration() {
|
||||
}
|
||||
|
||||
public static NullEnumeration getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public
|
||||
boolean hasMoreElements() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public
|
||||
Object nextElement() {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
114
java/src/org/apache/log4j/helpers/OnlyOnceErrorHandler.java
Normal file
114
java/src/org/apache/log4j/helpers/OnlyOnceErrorHandler.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import org.apache.log4j.spi.ErrorHandler;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.Appender;
|
||||
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
/**
|
||||
|
||||
The <code>OnlyOnceErrorHandler</code> implements log4j's default
|
||||
error handling policy which consists of emitting a message for the
|
||||
first error in an appender and ignoring all following errors.
|
||||
|
||||
<p>The error message is printed on <code>System.err</code>.
|
||||
|
||||
<p>This policy aims at protecting an otherwise working application
|
||||
from being flooded with error messages when logging fails.
|
||||
|
||||
@author Ceki Gülcü
|
||||
@since 0.9.0 */
|
||||
public class OnlyOnceErrorHandler implements ErrorHandler {
|
||||
|
||||
|
||||
final String WARN_PREFIX = "log4j warning: ";
|
||||
final String ERROR_PREFIX = "log4j error: ";
|
||||
|
||||
boolean firstTime = true;
|
||||
|
||||
|
||||
/**
|
||||
Does not do anything.
|
||||
*/
|
||||
public
|
||||
void setLogger(Logger logger) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
No options to activate.
|
||||
*/
|
||||
public
|
||||
void activateOptions() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Prints the message and the stack trace of the exception on
|
||||
<code>System.err</code>. */
|
||||
public
|
||||
void error(String message, Exception e, int errorCode) {
|
||||
error(message, e, errorCode, null);
|
||||
}
|
||||
|
||||
/**
|
||||
Prints the message and the stack trace of the exception on
|
||||
<code>System.err</code>.
|
||||
*/
|
||||
public
|
||||
void error(String message, Exception e, int errorCode, LoggingEvent event) {
|
||||
if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
if(firstTime) {
|
||||
LogLog.error(message, e);
|
||||
firstTime = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Print a the error message passed as parameter on
|
||||
<code>System.err</code>.
|
||||
*/
|
||||
public
|
||||
void error(String message) {
|
||||
if(firstTime) {
|
||||
LogLog.error(message);
|
||||
firstTime = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Does not do anything.
|
||||
*/
|
||||
public
|
||||
void setAppender(Appender appender) {
|
||||
}
|
||||
|
||||
/**
|
||||
Does not do anything.
|
||||
*/
|
||||
public
|
||||
void setBackupAppender(Appender appender) {
|
||||
}
|
||||
}
|
||||
485
java/src/org/apache/log4j/helpers/OptionConverter.java
Normal file
485
java/src/org/apache/log4j/helpers/OptionConverter.java
Normal file
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.net.URL;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.spi.Configurator;
|
||||
import org.apache.log4j.spi.LoggerRepository;
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
|
||||
// Contributors: Avy Sharell (sharell@online.fr)
|
||||
// Matthieu Verbert (mve@zurich.ibm.com)
|
||||
// Colin Sampaleanu
|
||||
|
||||
/**
|
||||
A convenience class to convert property values to specific types.
|
||||
|
||||
@author Ceki Gülcü
|
||||
@author Simon Kitching;
|
||||
@author Anders Kristensen
|
||||
*/
|
||||
public class OptionConverter {
|
||||
|
||||
static String DELIM_START = "${";
|
||||
static char DELIM_STOP = '}';
|
||||
static int DELIM_START_LEN = 2;
|
||||
static int DELIM_STOP_LEN = 1;
|
||||
|
||||
/** OptionConverter is a static class. */
|
||||
private OptionConverter() {}
|
||||
|
||||
public
|
||||
static
|
||||
String[] concatanateArrays(String[] l, String[] r) {
|
||||
int len = l.length + r.length;
|
||||
String[] a = new String[len];
|
||||
|
||||
System.arraycopy(l, 0, a, 0, l.length);
|
||||
System.arraycopy(r, 0, a, l.length, r.length);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
public
|
||||
static
|
||||
String convertSpecialChars(String s) {
|
||||
char c;
|
||||
int len = s.length();
|
||||
StringBuffer sbuf = new StringBuffer(len);
|
||||
|
||||
int i = 0;
|
||||
while(i < len) {
|
||||
c = s.charAt(i++);
|
||||
if (c == '\\') {
|
||||
c = s.charAt(i++);
|
||||
if(c == 'n') c = '\n';
|
||||
else if(c == 'r') c = '\r';
|
||||
else if(c == 't') c = '\t';
|
||||
else if(c == 'f') c = '\f';
|
||||
else if(c == '\b') c = '\b';
|
||||
else if(c == '\"') c = '\"';
|
||||
else if(c == '\'') c = '\'';
|
||||
else if(c == '\\') c = '\\';
|
||||
}
|
||||
sbuf.append(c);
|
||||
}
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Very similar to <code>System.getProperty</code> except
|
||||
that the {@link SecurityException} is hidden.
|
||||
|
||||
@param key The key to search for.
|
||||
@param def The default value to return.
|
||||
@return the string value of the system property, or the default
|
||||
value if there is no property with that key.
|
||||
|
||||
@since 1.1 */
|
||||
public
|
||||
static
|
||||
String getSystemProperty(String key, String def) {
|
||||
try {
|
||||
return System.getProperty(key, def);
|
||||
} catch(Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx
|
||||
LogLog.debug("Was not allowed to read system property \""+key+"\".");
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
static
|
||||
Object instantiateByKey(Properties props, String key, Class superClass,
|
||||
Object defaultValue) {
|
||||
|
||||
// Get the value of the property in string form
|
||||
String className = findAndSubst(key, props);
|
||||
if(className == null) {
|
||||
LogLog.error("Could not find value for key " + key);
|
||||
return defaultValue;
|
||||
}
|
||||
// Trim className to avoid trailing spaces that cause problems.
|
||||
return OptionConverter.instantiateByClassName(className.trim(), superClass,
|
||||
defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
If <code>value</code> is "true", then <code>true</code> is
|
||||
returned. If <code>value</code> is "false", then
|
||||
<code>true</code> is returned. Otherwise, <code>default</code> is
|
||||
returned.
|
||||
|
||||
<p>Case of value is unimportant. */
|
||||
public
|
||||
static
|
||||
boolean toBoolean(String value, boolean dEfault) {
|
||||
if(value == null)
|
||||
return dEfault;
|
||||
String trimmedVal = value.trim();
|
||||
if("true".equalsIgnoreCase(trimmedVal))
|
||||
return true;
|
||||
if("false".equalsIgnoreCase(trimmedVal))
|
||||
return false;
|
||||
return dEfault;
|
||||
}
|
||||
|
||||
public
|
||||
static
|
||||
int toInt(String value, int dEfault) {
|
||||
if(value != null) {
|
||||
String s = value.trim();
|
||||
try {
|
||||
return Integer.valueOf(s).intValue();
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
LogLog.error("[" + s + "] is not in proper int form.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return dEfault;
|
||||
}
|
||||
|
||||
/**
|
||||
Converts a standard or custom priority level to a Level
|
||||
object. <p> If <code>value</code> is of form
|
||||
"level#classname", then the specified class' toLevel method
|
||||
is called to process the specified level string; if no '#'
|
||||
character is present, then the default {@link org.apache.log4j.Level}
|
||||
class is used to process the level value.
|
||||
|
||||
<p>As a special case, if the <code>value</code> parameter is
|
||||
equal to the string "NULL", then the value <code>null</code> will
|
||||
be returned.
|
||||
|
||||
<p> If any error occurs while converting the value to a level,
|
||||
the <code>defaultValue</code> parameter, which may be
|
||||
<code>null</code>, is returned.
|
||||
|
||||
<p> Case of <code>value</code> is insignificant for the level level, but is
|
||||
significant for the class name part, if present.
|
||||
|
||||
@since 1.1 */
|
||||
public
|
||||
static
|
||||
Level toLevel(String value, Level defaultValue) {
|
||||
if(value == null)
|
||||
return defaultValue;
|
||||
|
||||
value = value.trim();
|
||||
|
||||
int hashIndex = value.indexOf('#');
|
||||
if (hashIndex == -1) {
|
||||
if("NULL".equalsIgnoreCase(value)) {
|
||||
return null;
|
||||
} else {
|
||||
// no class name specified : use standard Level class
|
||||
return(Level) Level.toLevel(value, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
Level result = defaultValue;
|
||||
|
||||
String clazz = value.substring(hashIndex+1);
|
||||
String levelName = value.substring(0, hashIndex);
|
||||
|
||||
// This is degenerate case but you never know.
|
||||
if("NULL".equalsIgnoreCase(levelName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
LogLog.debug("toLevel" + ":class=[" + clazz + "]"
|
||||
+ ":pri=[" + levelName + "]");
|
||||
|
||||
try {
|
||||
Class customLevel = Loader.loadClass(clazz);
|
||||
|
||||
// get a ref to the specified class' static method
|
||||
// toLevel(String, org.apache.log4j.Level)
|
||||
Class[] paramTypes = new Class[] { String.class,
|
||||
org.apache.log4j.Level.class
|
||||
};
|
||||
java.lang.reflect.Method toLevelMethod =
|
||||
customLevel.getMethod("toLevel", paramTypes);
|
||||
|
||||
// now call the toLevel method, passing level string + default
|
||||
Object[] params = new Object[] {levelName, defaultValue};
|
||||
Object o = toLevelMethod.invoke(null, params);
|
||||
|
||||
result = (Level) o;
|
||||
} catch(ClassNotFoundException e) {
|
||||
LogLog.warn("custom level class [" + clazz + "] not found.");
|
||||
} catch(NoSuchMethodException e) {
|
||||
LogLog.warn("custom level class [" + clazz + "]"
|
||||
+ " does not have a class function toLevel(String, Level)", e);
|
||||
} catch(java.lang.reflect.InvocationTargetException e) {
|
||||
if (e.getTargetException() instanceof InterruptedException
|
||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
LogLog.warn("custom level class [" + clazz + "]"
|
||||
+ " could not be instantiated", e);
|
||||
} catch(ClassCastException e) {
|
||||
LogLog.warn("class [" + clazz
|
||||
+ "] is not a subclass of org.apache.log4j.Level", e);
|
||||
} catch(IllegalAccessException e) {
|
||||
LogLog.warn("class ["+clazz+
|
||||
"] cannot be instantiated due to access restrictions", e);
|
||||
} catch(RuntimeException e) {
|
||||
LogLog.warn("class ["+clazz+"], level ["+levelName+
|
||||
"] conversion failed.", e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public
|
||||
static
|
||||
long toFileSize(String value, long dEfault) {
|
||||
if(value == null)
|
||||
return dEfault;
|
||||
|
||||
String s = value.trim().toUpperCase();
|
||||
long multiplier = 1;
|
||||
int index;
|
||||
|
||||
if((index = s.indexOf("KB")) != -1) {
|
||||
multiplier = 1024;
|
||||
s = s.substring(0, index);
|
||||
}
|
||||
else if((index = s.indexOf("MB")) != -1) {
|
||||
multiplier = 1024*1024;
|
||||
s = s.substring(0, index);
|
||||
}
|
||||
else if((index = s.indexOf("GB")) != -1) {
|
||||
multiplier = 1024*1024*1024;
|
||||
s = s.substring(0, index);
|
||||
}
|
||||
if(s != null) {
|
||||
try {
|
||||
return Long.valueOf(s).longValue() * multiplier;
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
LogLog.error("[" + s + "] is not in proper int form.");
|
||||
LogLog.error("[" + value + "] not in expected format.", e);
|
||||
}
|
||||
}
|
||||
return dEfault;
|
||||
}
|
||||
|
||||
/**
|
||||
Find the value corresponding to <code>key</code> in
|
||||
<code>props</code>. Then perform variable substitution on the
|
||||
found value.
|
||||
|
||||
*/
|
||||
public
|
||||
static
|
||||
String findAndSubst(String key, Properties props) {
|
||||
String value = props.getProperty(key);
|
||||
if(value == null)
|
||||
return null;
|
||||
|
||||
try {
|
||||
return substVars(value, props);
|
||||
} catch(IllegalArgumentException e) {
|
||||
LogLog.error("Bad option value ["+value+"].", e);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate an object given a class name. Check that the
|
||||
<code>className</code> is a subclass of
|
||||
<code>superClass</code>. If that test fails or the object could
|
||||
not be instantiated, then <code>defaultValue</code> is returned.
|
||||
|
||||
@param className The fully qualified class name of the object to instantiate.
|
||||
@param superClass The class to which the new object should belong.
|
||||
@param defaultValue The object to return in case of non-fulfillment
|
||||
*/
|
||||
public
|
||||
static
|
||||
Object instantiateByClassName(String className, Class superClass,
|
||||
Object defaultValue) {
|
||||
if(className != null) {
|
||||
try {
|
||||
Class classObj = Loader.loadClass(className);
|
||||
if(!superClass.isAssignableFrom(classObj)) {
|
||||
LogLog.error("A \""+className+"\" object is not assignable to a \""+
|
||||
superClass.getName() + "\" variable.");
|
||||
LogLog.error("The class \""+ superClass.getName()+"\" was loaded by ");
|
||||
LogLog.error("["+superClass.getClassLoader()+"] whereas object of type ");
|
||||
LogLog.error("\"" +classObj.getName()+"\" was loaded by ["
|
||||
+classObj.getClassLoader()+"].");
|
||||
return defaultValue;
|
||||
}
|
||||
return classObj.newInstance();
|
||||
} catch (ClassNotFoundException e) {
|
||||
LogLog.error("Could not instantiate class [" + className + "].", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
LogLog.error("Could not instantiate class [" + className + "].", e);
|
||||
} catch (InstantiationException e) {
|
||||
LogLog.error("Could not instantiate class [" + className + "].", e);
|
||||
} catch (RuntimeException e) {
|
||||
LogLog.error("Could not instantiate class [" + className + "].", e);
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Perform variable substitution in string <code>val</code> from the
|
||||
values of keys found in the system propeties.
|
||||
|
||||
<p>The variable substitution delimeters are <b>${</b> and <b>}</b>.
|
||||
|
||||
<p>For example, if the System properties contains "key=value", then
|
||||
the call
|
||||
<pre>
|
||||
String s = OptionConverter.substituteVars("Value of key is ${key}.");
|
||||
</pre>
|
||||
|
||||
will set the variable <code>s</code> to "Value of key is value.".
|
||||
|
||||
<p>If no value could be found for the specified key, then the
|
||||
<code>props</code> parameter is searched, if the value could not
|
||||
be found there, then substitution defaults to the empty string.
|
||||
|
||||
<p>For example, if system propeties contains no value for the key
|
||||
"inexistentKey", then the call
|
||||
|
||||
<pre>
|
||||
String s = OptionConverter.subsVars("Value of inexistentKey is [${inexistentKey}]");
|
||||
</pre>
|
||||
will set <code>s</code> to "Value of inexistentKey is []"
|
||||
|
||||
<p>An {@link java.lang.IllegalArgumentException} is thrown if
|
||||
<code>val</code> contains a start delimeter "${" which is not
|
||||
balanced by a stop delimeter "}". </p>
|
||||
|
||||
<p><b>Author</b> Avy Sharell</a></p>
|
||||
|
||||
@param val The string on which variable substitution is performed.
|
||||
@throws IllegalArgumentException if <code>val</code> is malformed.
|
||||
|
||||
*/
|
||||
public static
|
||||
String substVars(String val, Properties props) throws
|
||||
IllegalArgumentException {
|
||||
|
||||
StringBuffer sbuf = new StringBuffer();
|
||||
|
||||
int i = 0;
|
||||
int j, k;
|
||||
|
||||
while(true) {
|
||||
j=val.indexOf(DELIM_START, i);
|
||||
if(j == -1) {
|
||||
// no more variables
|
||||
if(i==0) { // this is a simple string
|
||||
return val;
|
||||
} else { // add the tail string which contails no variables and return the result.
|
||||
sbuf.append(val.substring(i, val.length()));
|
||||
return sbuf.toString();
|
||||
}
|
||||
} else {
|
||||
sbuf.append(val.substring(i, j));
|
||||
k = val.indexOf(DELIM_STOP, j);
|
||||
if(k == -1) {
|
||||
throw new IllegalArgumentException('"'+val+
|
||||
"\" has no closing brace. Opening brace at position " + j
|
||||
+ '.');
|
||||
} else {
|
||||
j += DELIM_START_LEN;
|
||||
String key = val.substring(j, k);
|
||||
// first try in System properties
|
||||
String replacement = getSystemProperty(key, null);
|
||||
// then try props parameter
|
||||
if(replacement == null && props != null) {
|
||||
replacement = props.getProperty(key);
|
||||
}
|
||||
|
||||
if(replacement != null) {
|
||||
// Do variable substitution on the replacement string
|
||||
// such that we can solve "Hello ${x2}" as "Hello p1"
|
||||
// the where the properties are
|
||||
// x1=p1
|
||||
// x2=${x1}
|
||||
String recursiveReplacement = substVars(replacement, props);
|
||||
sbuf.append(recursiveReplacement);
|
||||
}
|
||||
i = k + DELIM_STOP_LEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Configure log4j given a URL.
|
||||
|
||||
<p>The url must point to a file or resource which will be interpreted by
|
||||
a new instance of a log4j configurator.
|
||||
|
||||
<p>All configurations steps are taken on the
|
||||
<code>hierarchy</code> passed as a parameter.
|
||||
|
||||
<p>
|
||||
@param url The location of the configuration file or resource.
|
||||
@param clazz The classname, of the log4j configurator which will parse
|
||||
the file or resource at <code>url</code>. This must be a subclass of
|
||||
{@link Configurator}, or null. If this value is null then a default
|
||||
configurator of {@link PropertyConfigurator} is used, unless the
|
||||
filename pointed to by <code>url</code> ends in '.xml', in which case
|
||||
{@link org.apache.log4j.xml.DOMConfigurator} is used.
|
||||
@param hierarchy The {@link org.apache.log4j.Hierarchy} to act on.
|
||||
|
||||
@since 1.1.4 */
|
||||
|
||||
static
|
||||
public
|
||||
void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {
|
||||
Configurator configurator = null;
|
||||
String filename = url.getFile();
|
||||
|
||||
if(clazz == null && filename != null && filename.endsWith(".xml")) {
|
||||
clazz = "org.apache.log4j.xml.DOMConfigurator";
|
||||
}
|
||||
|
||||
if(clazz != null) {
|
||||
LogLog.debug("Preferred configurator class: " + clazz);
|
||||
configurator = (Configurator) instantiateByClassName(clazz,
|
||||
Configurator.class,
|
||||
null);
|
||||
if(configurator == null) {
|
||||
LogLog.error("Could not instantiate configurator ["+clazz+"].");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
configurator = new PropertyConfigurator();
|
||||
}
|
||||
|
||||
configurator.doConfigure(url, hierarchy);
|
||||
}
|
||||
}
|
||||
111
java/src/org/apache/log4j/helpers/PatternConverter.java
Normal file
111
java/src/org/apache/log4j/helpers/PatternConverter.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
/**
|
||||
|
||||
<p>PatternConverter is an abtract class that provides the
|
||||
formatting functionality that derived classes need.
|
||||
|
||||
<p>Conversion specifiers in a conversion patterns are parsed to
|
||||
individual PatternConverters. Each of which is responsible for
|
||||
converting a logging event in a converter specific manner.
|
||||
|
||||
@author <a href="mailto:cakalijp@Maritz.com">James P. Cakalic</a>
|
||||
@author Ceki Gülcü
|
||||
|
||||
@since 0.8.2
|
||||
*/
|
||||
public abstract class PatternConverter {
|
||||
public PatternConverter next;
|
||||
int min = -1;
|
||||
int max = 0x7FFFFFFF;
|
||||
boolean leftAlign = false;
|
||||
|
||||
protected
|
||||
PatternConverter() { }
|
||||
|
||||
protected
|
||||
PatternConverter(FormattingInfo fi) {
|
||||
min = fi.min;
|
||||
max = fi.max;
|
||||
leftAlign = fi.leftAlign;
|
||||
}
|
||||
|
||||
/**
|
||||
Derived pattern converters must override this method in order to
|
||||
convert conversion specifiers in the correct way.
|
||||
*/
|
||||
abstract
|
||||
protected
|
||||
String convert(LoggingEvent event);
|
||||
|
||||
/**
|
||||
A template method for formatting in a converter specific way.
|
||||
*/
|
||||
public
|
||||
void format(StringBuffer sbuf, LoggingEvent e) {
|
||||
String s = convert(e);
|
||||
|
||||
if(s == null) {
|
||||
if(0 < min)
|
||||
spacePad(sbuf, min);
|
||||
return;
|
||||
}
|
||||
|
||||
int len = s.length();
|
||||
|
||||
if(len > max)
|
||||
sbuf.append(s.substring(len-max));
|
||||
else if(len < min) {
|
||||
if(leftAlign) {
|
||||
sbuf.append(s);
|
||||
spacePad(sbuf, min-len);
|
||||
}
|
||||
else {
|
||||
spacePad(sbuf, min-len);
|
||||
sbuf.append(s);
|
||||
}
|
||||
}
|
||||
else
|
||||
sbuf.append(s);
|
||||
}
|
||||
|
||||
static String[] SPACES = {" ", " ", " ", " ", //1,2,4,8 spaces
|
||||
" ", // 16 spaces
|
||||
" " }; // 32 spaces
|
||||
|
||||
/**
|
||||
Fast space padding method.
|
||||
*/
|
||||
public
|
||||
void spacePad(StringBuffer sbuf, int length) {
|
||||
while(length >= 32) {
|
||||
sbuf.append(SPACES[5]);
|
||||
length -= 32;
|
||||
}
|
||||
|
||||
for(int i = 4; i >= 0; i--) {
|
||||
if((length & (1<<i)) != 0) {
|
||||
sbuf.append(SPACES[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
570
java/src/org/apache/log4j/helpers/PatternParser.java
Normal file
570
java/src/org/apache/log4j/helpers/PatternParser.java
Normal file
@@ -0,0 +1,570 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import org.apache.log4j.Layout;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
import org.apache.log4j.spi.LocationInfo;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Arrays;
|
||||
|
||||
// Contributors: Nelson Minar <(nelson@monkey.org>
|
||||
// Igor E. Poteryaev <jah@mail.ru>
|
||||
// Reinhard Deschler <reinhard.deschler@web.de>
|
||||
|
||||
/**
|
||||
Most of the work of the {@link org.apache.log4j.PatternLayout} class
|
||||
is delegated to the PatternParser class.
|
||||
|
||||
<p>It is this class that parses conversion patterns and creates
|
||||
a chained list of {@link OptionConverter OptionConverters}.
|
||||
|
||||
@author <a href=mailto:"cakalijp@Maritz.com">James P. Cakalic</a>
|
||||
@author Ceki Gülcü
|
||||
@author Anders Kristensen
|
||||
|
||||
@since 0.8.2
|
||||
*/
|
||||
public class PatternParser {
|
||||
|
||||
private static final char ESCAPE_CHAR = '%';
|
||||
|
||||
private static final int LITERAL_STATE = 0;
|
||||
private static final int CONVERTER_STATE = 1;
|
||||
private static final int DOT_STATE = 3;
|
||||
private static final int MIN_STATE = 4;
|
||||
private static final int MAX_STATE = 5;
|
||||
|
||||
static final int FULL_LOCATION_CONVERTER = 1000;
|
||||
static final int METHOD_LOCATION_CONVERTER = 1001;
|
||||
static final int CLASS_LOCATION_CONVERTER = 1002;
|
||||
static final int LINE_LOCATION_CONVERTER = 1003;
|
||||
static final int FILE_LOCATION_CONVERTER = 1004;
|
||||
|
||||
static final int RELATIVE_TIME_CONVERTER = 2000;
|
||||
static final int THREAD_CONVERTER = 2001;
|
||||
static final int LEVEL_CONVERTER = 2002;
|
||||
static final int NDC_CONVERTER = 2003;
|
||||
static final int MESSAGE_CONVERTER = 2004;
|
||||
|
||||
int state;
|
||||
protected StringBuffer currentLiteral = new StringBuffer(32);
|
||||
protected int patternLength;
|
||||
protected int i;
|
||||
PatternConverter head;
|
||||
PatternConverter tail;
|
||||
protected FormattingInfo formattingInfo = new FormattingInfo();
|
||||
protected String pattern;
|
||||
|
||||
public
|
||||
PatternParser(String pattern) {
|
||||
this.pattern = pattern;
|
||||
patternLength = pattern.length();
|
||||
state = LITERAL_STATE;
|
||||
}
|
||||
|
||||
private
|
||||
void addToList(PatternConverter pc) {
|
||||
if(head == null) {
|
||||
head = tail = pc;
|
||||
} else {
|
||||
tail.next = pc;
|
||||
tail = pc;
|
||||
}
|
||||
}
|
||||
|
||||
protected
|
||||
String extractOption() {
|
||||
if((i < patternLength) && (pattern.charAt(i) == '{')) {
|
||||
int end = pattern.indexOf('}', i);
|
||||
if (end > i) {
|
||||
String r = pattern.substring(i + 1, end);
|
||||
i = end+1;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The option is expected to be in decimal and positive. In case of
|
||||
error, zero is returned. */
|
||||
protected
|
||||
int extractPrecisionOption() {
|
||||
String opt = extractOption();
|
||||
int r = 0;
|
||||
if(opt != null) {
|
||||
try {
|
||||
r = Integer.parseInt(opt);
|
||||
if(r <= 0) {
|
||||
LogLog.error(
|
||||
"Precision option (" + opt + ") isn't a positive integer.");
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
LogLog.error("Category option \""+opt+"\" not a decimal integer.", e);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public
|
||||
PatternConverter parse() {
|
||||
char c;
|
||||
i = 0;
|
||||
while(i < patternLength) {
|
||||
c = pattern.charAt(i++);
|
||||
switch(state) {
|
||||
case LITERAL_STATE:
|
||||
// In literal state, the last char is always a literal.
|
||||
if(i == patternLength) {
|
||||
currentLiteral.append(c);
|
||||
continue;
|
||||
}
|
||||
if(c == ESCAPE_CHAR) {
|
||||
// peek at the next char.
|
||||
switch(pattern.charAt(i)) {
|
||||
case ESCAPE_CHAR:
|
||||
currentLiteral.append(c);
|
||||
i++; // move pointer
|
||||
break;
|
||||
case 'n':
|
||||
currentLiteral.append(Layout.LINE_SEP);
|
||||
i++; // move pointer
|
||||
break;
|
||||
default:
|
||||
if(currentLiteral.length() != 0) {
|
||||
addToList(new LiteralPatternConverter(
|
||||
currentLiteral.toString()));
|
||||
//LogLog.debug("Parsed LITERAL converter: \""
|
||||
// +currentLiteral+"\".");
|
||||
}
|
||||
currentLiteral.setLength(0);
|
||||
currentLiteral.append(c); // append %
|
||||
state = CONVERTER_STATE;
|
||||
formattingInfo.reset();
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentLiteral.append(c);
|
||||
}
|
||||
break;
|
||||
case CONVERTER_STATE:
|
||||
currentLiteral.append(c);
|
||||
switch(c) {
|
||||
case '-':
|
||||
formattingInfo.leftAlign = true;
|
||||
break;
|
||||
case '.':
|
||||
state = DOT_STATE;
|
||||
break;
|
||||
default:
|
||||
if(c >= '0' && c <= '9') {
|
||||
formattingInfo.min = c - '0';
|
||||
state = MIN_STATE;
|
||||
}
|
||||
else
|
||||
finalizeConverter(c);
|
||||
} // switch
|
||||
break;
|
||||
case MIN_STATE:
|
||||
currentLiteral.append(c);
|
||||
if(c >= '0' && c <= '9')
|
||||
formattingInfo.min = formattingInfo.min*10 + (c - '0');
|
||||
else if(c == '.')
|
||||
state = DOT_STATE;
|
||||
else {
|
||||
finalizeConverter(c);
|
||||
}
|
||||
break;
|
||||
case DOT_STATE:
|
||||
currentLiteral.append(c);
|
||||
if(c >= '0' && c <= '9') {
|
||||
formattingInfo.max = c - '0';
|
||||
state = MAX_STATE;
|
||||
}
|
||||
else {
|
||||
LogLog.error("Error occured in position "+i
|
||||
+".\n Was expecting digit, instead got char \""+c+"\".");
|
||||
state = LITERAL_STATE;
|
||||
}
|
||||
break;
|
||||
case MAX_STATE:
|
||||
currentLiteral.append(c);
|
||||
if(c >= '0' && c <= '9')
|
||||
formattingInfo.max = formattingInfo.max*10 + (c - '0');
|
||||
else {
|
||||
finalizeConverter(c);
|
||||
state = LITERAL_STATE;
|
||||
}
|
||||
break;
|
||||
} // switch
|
||||
} // while
|
||||
if(currentLiteral.length() != 0) {
|
||||
addToList(new LiteralPatternConverter(currentLiteral.toString()));
|
||||
//LogLog.debug("Parsed LITERAL converter: \""+currentLiteral+"\".");
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
protected
|
||||
void finalizeConverter(char c) {
|
||||
PatternConverter pc = null;
|
||||
switch(c) {
|
||||
case 'c':
|
||||
pc = new CategoryPatternConverter(formattingInfo,
|
||||
extractPrecisionOption());
|
||||
//LogLog.debug("CATEGORY converter.");
|
||||
//formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
case 'C':
|
||||
pc = new ClassNamePatternConverter(formattingInfo,
|
||||
extractPrecisionOption());
|
||||
//LogLog.debug("CLASS_NAME converter.");
|
||||
//formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
case 'd':
|
||||
String dateFormatStr = AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT;
|
||||
DateFormat df;
|
||||
String dOpt = extractOption();
|
||||
if(dOpt != null)
|
||||
dateFormatStr = dOpt;
|
||||
|
||||
if(dateFormatStr.equalsIgnoreCase(
|
||||
AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT))
|
||||
df = new ISO8601DateFormat();
|
||||
else if(dateFormatStr.equalsIgnoreCase(
|
||||
AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT))
|
||||
df = new AbsoluteTimeDateFormat();
|
||||
else if(dateFormatStr.equalsIgnoreCase(
|
||||
AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT))
|
||||
df = new DateTimeDateFormat();
|
||||
else {
|
||||
try {
|
||||
df = new SimpleDateFormat(dateFormatStr);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
LogLog.error("Could not instantiate SimpleDateFormat with " +
|
||||
dateFormatStr, e);
|
||||
df = (DateFormat) OptionConverter.instantiateByClassName(
|
||||
"org.apache.log4j.helpers.ISO8601DateFormat",
|
||||
DateFormat.class, null);
|
||||
}
|
||||
}
|
||||
pc = new DatePatternConverter(formattingInfo, df);
|
||||
//LogLog.debug("DATE converter {"+dateFormatStr+"}.");
|
||||
//formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
case 'F':
|
||||
pc = new LocationPatternConverter(formattingInfo,
|
||||
FILE_LOCATION_CONVERTER);
|
||||
//LogLog.debug("File name converter.");
|
||||
//formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
case 'l':
|
||||
pc = new LocationPatternConverter(formattingInfo,
|
||||
FULL_LOCATION_CONVERTER);
|
||||
//LogLog.debug("Location converter.");
|
||||
//formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
case 'L':
|
||||
pc = new LocationPatternConverter(formattingInfo,
|
||||
LINE_LOCATION_CONVERTER);
|
||||
//LogLog.debug("LINE NUMBER converter.");
|
||||
//formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
case 'm':
|
||||
pc = new BasicPatternConverter(formattingInfo, MESSAGE_CONVERTER);
|
||||
//LogLog.debug("MESSAGE converter.");
|
||||
//formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
case 'M':
|
||||
pc = new LocationPatternConverter(formattingInfo,
|
||||
METHOD_LOCATION_CONVERTER);
|
||||
//LogLog.debug("METHOD converter.");
|
||||
//formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
case 'p':
|
||||
pc = new BasicPatternConverter(formattingInfo, LEVEL_CONVERTER);
|
||||
//LogLog.debug("LEVEL converter.");
|
||||
//formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
case 'r':
|
||||
pc = new BasicPatternConverter(formattingInfo,
|
||||
RELATIVE_TIME_CONVERTER);
|
||||
//LogLog.debug("RELATIVE time converter.");
|
||||
//formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
case 't':
|
||||
pc = new BasicPatternConverter(formattingInfo, THREAD_CONVERTER);
|
||||
//LogLog.debug("THREAD converter.");
|
||||
//formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
/*case 'u':
|
||||
if(i < patternLength) {
|
||||
char cNext = pattern.charAt(i);
|
||||
if(cNext >= '0' && cNext <= '9') {
|
||||
pc = new UserFieldPatternConverter(formattingInfo, cNext - '0');
|
||||
LogLog.debug("USER converter ["+cNext+"].");
|
||||
formattingInfo.dump();
|
||||
currentLiteral.setLength(0);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
LogLog.error("Unexpected char" +cNext+" at position "+i);
|
||||
}
|
||||
break;*/
|
||||
case 'x':
|
||||
pc = new BasicPatternConverter(formattingInfo, NDC_CONVERTER);
|
||||
//LogLog.debug("NDC converter.");
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
case 'X':
|
||||
String xOpt = extractOption();
|
||||
pc = new MDCPatternConverter(formattingInfo, xOpt);
|
||||
currentLiteral.setLength(0);
|
||||
break;
|
||||
default:
|
||||
LogLog.error("Unexpected char [" +c+"] at position "+i
|
||||
+" in conversion patterrn.");
|
||||
pc = new LiteralPatternConverter(currentLiteral.toString());
|
||||
currentLiteral.setLength(0);
|
||||
}
|
||||
|
||||
addConverter(pc);
|
||||
}
|
||||
|
||||
protected
|
||||
void addConverter(PatternConverter pc) {
|
||||
currentLiteral.setLength(0);
|
||||
// Add the pattern converter to the list.
|
||||
addToList(pc);
|
||||
// Next pattern is assumed to be a literal.
|
||||
state = LITERAL_STATE;
|
||||
// Reset formatting info
|
||||
formattingInfo.reset();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// PatternConverters
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private static class BasicPatternConverter extends PatternConverter {
|
||||
int type;
|
||||
|
||||
BasicPatternConverter(FormattingInfo formattingInfo, int type) {
|
||||
super(formattingInfo);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public
|
||||
String convert(LoggingEvent event) {
|
||||
switch(type) {
|
||||
case RELATIVE_TIME_CONVERTER:
|
||||
return (Long.toString(event.timeStamp - LoggingEvent.getStartTime()));
|
||||
case THREAD_CONVERTER:
|
||||
return event.getThreadName();
|
||||
case LEVEL_CONVERTER:
|
||||
return event.getLevel().toString();
|
||||
case NDC_CONVERTER:
|
||||
return event.getNDC();
|
||||
case MESSAGE_CONVERTER: {
|
||||
return event.getRenderedMessage();
|
||||
}
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class LiteralPatternConverter extends PatternConverter {
|
||||
private String literal;
|
||||
|
||||
LiteralPatternConverter(String value) {
|
||||
literal = value;
|
||||
}
|
||||
|
||||
public
|
||||
final
|
||||
void format(StringBuffer sbuf, LoggingEvent event) {
|
||||
sbuf.append(literal);
|
||||
}
|
||||
|
||||
public
|
||||
String convert(LoggingEvent event) {
|
||||
return literal;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DatePatternConverter extends PatternConverter {
|
||||
private DateFormat df;
|
||||
private Date date;
|
||||
|
||||
DatePatternConverter(FormattingInfo formattingInfo, DateFormat df) {
|
||||
super(formattingInfo);
|
||||
date = new Date();
|
||||
this.df = df;
|
||||
}
|
||||
|
||||
public
|
||||
String convert(LoggingEvent event) {
|
||||
date.setTime(event.timeStamp);
|
||||
String converted = null;
|
||||
try {
|
||||
converted = df.format(date);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
LogLog.error("Error occured while converting date.", ex);
|
||||
}
|
||||
return converted;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MDCPatternConverter extends PatternConverter {
|
||||
private String key;
|
||||
|
||||
MDCPatternConverter(FormattingInfo formattingInfo, String key) {
|
||||
super(formattingInfo);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public
|
||||
String convert(LoggingEvent event) {
|
||||
if (key == null) {
|
||||
StringBuffer buf = new StringBuffer("{");
|
||||
Map properties = event.getProperties();
|
||||
if (properties.size() > 0) {
|
||||
Object[] keys = properties.keySet().toArray();
|
||||
Arrays.sort(keys);
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
buf.append('{');
|
||||
buf.append(keys[i]);
|
||||
buf.append(',');
|
||||
buf.append(properties.get(keys[i]));
|
||||
buf.append('}');
|
||||
}
|
||||
}
|
||||
buf.append('}');
|
||||
return buf.toString();
|
||||
} else {
|
||||
Object val = event.getMDC(key);
|
||||
if(val == null) {
|
||||
return null;
|
||||
} else {
|
||||
return val.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class LocationPatternConverter extends PatternConverter {
|
||||
int type;
|
||||
|
||||
LocationPatternConverter(FormattingInfo formattingInfo, int type) {
|
||||
super(formattingInfo);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public
|
||||
String convert(LoggingEvent event) {
|
||||
LocationInfo locationInfo = event.getLocationInformation();
|
||||
switch(type) {
|
||||
case FULL_LOCATION_CONVERTER:
|
||||
return locationInfo.fullInfo;
|
||||
case METHOD_LOCATION_CONVERTER:
|
||||
return locationInfo.getMethodName();
|
||||
case LINE_LOCATION_CONVERTER:
|
||||
return locationInfo.getLineNumber();
|
||||
case FILE_LOCATION_CONVERTER:
|
||||
return locationInfo.getFileName();
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class NamedPatternConverter extends PatternConverter {
|
||||
int precision;
|
||||
|
||||
NamedPatternConverter(FormattingInfo formattingInfo, int precision) {
|
||||
super(formattingInfo);
|
||||
this.precision = precision;
|
||||
}
|
||||
|
||||
abstract
|
||||
String getFullyQualifiedName(LoggingEvent event);
|
||||
|
||||
public
|
||||
String convert(LoggingEvent event) {
|
||||
String n = getFullyQualifiedName(event);
|
||||
if(precision <= 0)
|
||||
return n;
|
||||
else {
|
||||
int len = n.length();
|
||||
|
||||
// We substract 1 from 'len' when assigning to 'end' to avoid out of
|
||||
// bounds exception in return r.substring(end+1, len). This can happen if
|
||||
// precision is 1 and the category name ends with a dot.
|
||||
int end = len -1 ;
|
||||
for(int i = precision; i > 0; i--) {
|
||||
end = n.lastIndexOf('.', end-1);
|
||||
if(end == -1)
|
||||
return n;
|
||||
}
|
||||
return n.substring(end+1, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ClassNamePatternConverter extends NamedPatternConverter {
|
||||
|
||||
ClassNamePatternConverter(FormattingInfo formattingInfo, int precision) {
|
||||
super(formattingInfo, precision);
|
||||
}
|
||||
|
||||
String getFullyQualifiedName(LoggingEvent event) {
|
||||
return event.getLocationInformation().getClassName();
|
||||
}
|
||||
}
|
||||
|
||||
private class CategoryPatternConverter extends NamedPatternConverter {
|
||||
|
||||
CategoryPatternConverter(FormattingInfo formattingInfo, int precision) {
|
||||
super(formattingInfo, precision);
|
||||
}
|
||||
|
||||
String getFullyQualifiedName(LoggingEvent event) {
|
||||
return event.getLoggerName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
76
java/src/org/apache/log4j/helpers/QuietWriter.java
Normal file
76
java/src/org/apache/log4j/helpers/QuietWriter.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.io.FilterWriter;
|
||||
import org.apache.log4j.spi.ErrorHandler;
|
||||
import org.apache.log4j.spi.ErrorCode;
|
||||
|
||||
|
||||
/**
|
||||
QuietWriter does not throw exceptions when things go
|
||||
wrong. Instead, it delegates error handling to its {@link ErrorHandler}.
|
||||
|
||||
@author Ceki Gülcü
|
||||
|
||||
@since 0.7.3
|
||||
*/
|
||||
public class QuietWriter extends FilterWriter {
|
||||
|
||||
protected ErrorHandler errorHandler;
|
||||
|
||||
public
|
||||
QuietWriter(Writer writer, ErrorHandler errorHandler) {
|
||||
super(writer);
|
||||
setErrorHandler(errorHandler);
|
||||
}
|
||||
|
||||
public
|
||||
void write(String string) {
|
||||
if (string != null) {
|
||||
try {
|
||||
out.write(string);
|
||||
} catch(Exception e) {
|
||||
errorHandler.error("Failed to write ["+string+"].", e,
|
||||
ErrorCode.WRITE_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
void flush() {
|
||||
try {
|
||||
out.flush();
|
||||
} catch(Exception e) {
|
||||
errorHandler.error("Failed to flush writer,", e,
|
||||
ErrorCode.FLUSH_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
void setErrorHandler(ErrorHandler eh) {
|
||||
if(eh == null) {
|
||||
// This is a programming error on the part of the enclosing appender.
|
||||
throw new IllegalArgumentException("Attempted to set null ErrorHandler.");
|
||||
} else {
|
||||
this.errorHandler = eh;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import java.util.Date;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.ParsePosition;
|
||||
import java.text.DateFormat;
|
||||
|
||||
/**
|
||||
Formats a {@link Date} by printing the number of milliseconds
|
||||
elapsed since construction of the format. This is the fastest
|
||||
printing DateFormat in the package.
|
||||
|
||||
@author Ceki Gülcü
|
||||
|
||||
@since 0.7.5
|
||||
*/
|
||||
public class RelativeTimeDateFormat extends DateFormat {
|
||||
private static final long serialVersionUID = 7055751607085611984L;
|
||||
|
||||
|
||||
protected final long startTime;
|
||||
|
||||
public
|
||||
RelativeTimeDateFormat() {
|
||||
this.startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
Appends to <code>sbuf</code> the number of milliseconds elapsed
|
||||
since the start of the application.
|
||||
|
||||
@since 0.7.5
|
||||
*/
|
||||
public
|
||||
StringBuffer format(Date date, StringBuffer sbuf,
|
||||
FieldPosition fieldPosition) {
|
||||
//System.err.println(":"+ date.getTime() + " - " + startTime);
|
||||
return sbuf.append((date.getTime() - startTime));
|
||||
}
|
||||
|
||||
/**
|
||||
This method does not do anything but return <code>null</code>.
|
||||
*/
|
||||
public
|
||||
Date parse(java.lang.String s, ParsePosition pos) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
56
java/src/org/apache/log4j/helpers/SyslogQuietWriter.java
Normal file
56
java/src/org/apache/log4j/helpers/SyslogQuietWriter.java
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
|
||||
|
||||
import java.io.Writer;
|
||||
import org.apache.log4j.spi.ErrorHandler;
|
||||
|
||||
/**
|
||||
SyslogQuietWriter extends QuietWriter by prepending the syslog
|
||||
level code before each printed String.
|
||||
|
||||
@since 0.7.3
|
||||
*/
|
||||
public class SyslogQuietWriter extends QuietWriter {
|
||||
|
||||
int syslogFacility;
|
||||
int level;
|
||||
|
||||
public
|
||||
SyslogQuietWriter(Writer writer, int syslogFacility, ErrorHandler eh) {
|
||||
super(writer, eh);
|
||||
this.syslogFacility = syslogFacility;
|
||||
}
|
||||
|
||||
public
|
||||
void setLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public
|
||||
void setSyslogFacility(int syslogFacility) {
|
||||
this.syslogFacility = syslogFacility;
|
||||
}
|
||||
|
||||
public
|
||||
void write(String string) {
|
||||
super.write("<"+(syslogFacility | level)+">" + string);
|
||||
}
|
||||
}
|
||||
145
java/src/org/apache/log4j/helpers/SyslogWriter.java
Normal file
145
java/src/org/apache/log4j/helpers/SyslogWriter.java
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
|
||||
import java.io.Writer;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.SocketException;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
/**
|
||||
SyslogWriter is a wrapper around the java.net.DatagramSocket class
|
||||
so that it behaves like a java.io.Writer.
|
||||
|
||||
@since 0.7.3
|
||||
*/
|
||||
public class SyslogWriter extends Writer {
|
||||
|
||||
final int SYSLOG_PORT = 514;
|
||||
/**
|
||||
* Host string from last constructed SyslogWriter.
|
||||
* @deprecated
|
||||
*/
|
||||
static String syslogHost;
|
||||
|
||||
private InetAddress address;
|
||||
private final int port;
|
||||
private DatagramSocket ds;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of SyslogWriter.
|
||||
* @param syslogHost host name, may not be null. A port
|
||||
* may be specified by following the name or IPv4 literal address with
|
||||
* a colon and a decimal port number. To specify a port with an IPv6
|
||||
* address, enclose the IPv6 address in square brackets before appending
|
||||
* the colon and decimal port number.
|
||||
*/
|
||||
public
|
||||
SyslogWriter(final String syslogHost) {
|
||||
SyslogWriter.syslogHost = syslogHost;
|
||||
if (syslogHost == null) {
|
||||
throw new NullPointerException("syslogHost");
|
||||
}
|
||||
|
||||
String host = syslogHost;
|
||||
int urlPort = -1;
|
||||
|
||||
//
|
||||
// If not an unbracketed IPv6 address then
|
||||
// parse as a URL
|
||||
//
|
||||
if (host.indexOf("[") != -1 || host.indexOf(':') == host.lastIndexOf(':')) {
|
||||
try {
|
||||
URL url = new URL("http://" + host);
|
||||
if (url.getHost() != null) {
|
||||
host = url.getHost();
|
||||
// if host is a IPv6 literal, strip off the brackets
|
||||
if(host.startsWith("[") && host.charAt(host.length() - 1) == ']') {
|
||||
host = host.substring(1, host.length() - 1);
|
||||
}
|
||||
urlPort = url.getPort();
|
||||
}
|
||||
} catch(MalformedURLException e) {
|
||||
LogLog.error("Malformed URL: will attempt to interpret as InetAddress.", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (urlPort == -1) {
|
||||
urlPort = SYSLOG_PORT;
|
||||
}
|
||||
port = urlPort;
|
||||
|
||||
try {
|
||||
this.address = InetAddress.getByName(host);
|
||||
}
|
||||
catch (UnknownHostException e) {
|
||||
LogLog.error("Could not find " + host +
|
||||
". All logging will FAIL.", e);
|
||||
}
|
||||
|
||||
try {
|
||||
this.ds = new DatagramSocket();
|
||||
}
|
||||
catch (SocketException e) {
|
||||
e.printStackTrace();
|
||||
LogLog.error("Could not instantiate DatagramSocket to " + host +
|
||||
". All logging will FAIL.", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
void write(char[] buf, int off, int len) throws IOException {
|
||||
this.write(new String(buf, off, len));
|
||||
}
|
||||
|
||||
public
|
||||
void write(final String string) throws IOException {
|
||||
|
||||
if(this.ds != null && this.address != null) {
|
||||
byte[] bytes = string.getBytes();
|
||||
//
|
||||
// syslog packets must be less than 1024 bytes
|
||||
//
|
||||
int bytesLength = bytes.length;
|
||||
if (bytesLength >= 1024) {
|
||||
bytesLength = 1024;
|
||||
}
|
||||
DatagramPacket packet = new DatagramPacket(bytes, bytesLength,
|
||||
address, port);
|
||||
ds.send(packet);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public
|
||||
void flush() {}
|
||||
|
||||
public void close() {
|
||||
if (ds != null) {
|
||||
ds.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
java/src/org/apache/log4j/helpers/ThreadLocalMap.java
Normal file
42
java/src/org/apache/log4j/helpers/ThreadLocalMap.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
<code>ThreadLocalMap</code> extends {@link InheritableThreadLocal}
|
||||
to bequeath a copy of the hashtable of the MDC of the parent
|
||||
thread.
|
||||
|
||||
@author Ceki Gülcü
|
||||
@since 1.2
|
||||
*/
|
||||
final public class ThreadLocalMap extends InheritableThreadLocal {
|
||||
|
||||
public
|
||||
final
|
||||
Object childValue(Object parentValue) {
|
||||
Hashtable ht = (Hashtable) parentValue;
|
||||
if(ht != null) {
|
||||
return ht.clone();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
113
java/src/org/apache/log4j/helpers/Transform.java
Normal file
113
java/src/org/apache/log4j/helpers/Transform.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.helpers;
|
||||
|
||||
/**
|
||||
Utility class for transforming strings.
|
||||
|
||||
@author Ceki Gülcü
|
||||
@author Michael A. McAngus
|
||||
*/
|
||||
public class Transform {
|
||||
|
||||
private static final String CDATA_START = "<![CDATA[";
|
||||
private static final String CDATA_END = "]]>";
|
||||
private static final String CDATA_PSEUDO_END = "]]>";
|
||||
private static final String CDATA_EMBEDED_END = CDATA_END + CDATA_PSEUDO_END + CDATA_START;
|
||||
private static final int CDATA_END_LEN = CDATA_END.length();
|
||||
|
||||
/**
|
||||
* This method takes a string which may contain HTML tags (ie,
|
||||
* <b>, <table>, etc) and replaces any
|
||||
* '<', '>' , '&' or '"'
|
||||
* characters with respective predefined entity references.
|
||||
*
|
||||
* @param input The text to be converted.
|
||||
* @return The input string with the special characters replaced.
|
||||
* */
|
||||
static public String escapeTags(final String input) {
|
||||
//Check if the string is null, zero length or devoid of special characters
|
||||
// if so, return what was sent in.
|
||||
|
||||
if(input == null
|
||||
|| input.length() == 0
|
||||
|| (input.indexOf('"') == -1 &&
|
||||
input.indexOf('&') == -1 &&
|
||||
input.indexOf('<') == -1 &&
|
||||
input.indexOf('>') == -1)) {
|
||||
return input;
|
||||
}
|
||||
|
||||
//Use a StringBuffer in lieu of String concatenation -- it is
|
||||
//much more efficient this way.
|
||||
|
||||
StringBuffer buf = new StringBuffer(input.length() + 6);
|
||||
char ch = ' ';
|
||||
|
||||
int len = input.length();
|
||||
for(int i=0; i < len; i++) {
|
||||
ch = input.charAt(i);
|
||||
if (ch > '>') {
|
||||
buf.append(ch);
|
||||
} else if(ch == '<') {
|
||||
buf.append("<");
|
||||
} else if(ch == '>') {
|
||||
buf.append(">");
|
||||
} else if(ch == '&') {
|
||||
buf.append("&");
|
||||
} else if(ch == '"') {
|
||||
buf.append(""");
|
||||
} else {
|
||||
buf.append(ch);
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that embeded CDEnd strings (]]>) are handled properly
|
||||
* within message, NDC and throwable tag text.
|
||||
*
|
||||
* @param buf StringBuffer holding the XML data to this point. The
|
||||
* initial CDStart (<![CDATA[) and final CDEnd (]]>) of the CDATA
|
||||
* section are the responsibility of the calling method.
|
||||
* @param str The String that is inserted into an existing CDATA Section within buf.
|
||||
* */
|
||||
static public void appendEscapingCDATA(final StringBuffer buf,
|
||||
final String str) {
|
||||
if (str != null) {
|
||||
int end = str.indexOf(CDATA_END);
|
||||
if (end < 0) {
|
||||
buf.append(str);
|
||||
} else {
|
||||
int start = 0;
|
||||
while (end > -1) {
|
||||
buf.append(str.substring(start, end));
|
||||
buf.append(CDATA_EMBEDED_END);
|
||||
start = end + CDATA_END_LEN;
|
||||
if (start < str.length()) {
|
||||
end = str.indexOf(CDATA_END, start);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
buf.append(str.substring(start));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
java/src/org/apache/log4j/helpers/package.html
Normal file
33
java/src/org/apache/log4j/helpers/package.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You 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.
|
||||
|
||||
-->
|
||||
<html> <head>
|
||||
<title></title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<p>This package is used internally.
|
||||
|
||||
|
||||
<hr>
|
||||
<address></address>
|
||||
<!-- hhmts start -->
|
||||
Last modified: Sat Jul 3 15:12:58 MDT 1999
|
||||
<!-- hhmts end -->
|
||||
</body> </html>
|
||||
398
java/src/org/apache/log4j/jdbc/JDBCAppender.java
Normal file
398
java/src/org/apache/log4j/jdbc/JDBCAppender.java
Normal file
@@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
package org.apache.log4j.jdbc;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.apache.log4j.PatternLayout;
|
||||
import org.apache.log4j.spi.ErrorCode;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
|
||||
/**
|
||||
The JDBCAppender provides for sending log events to a database.
|
||||
|
||||
<p><b><font color="#FF2222">WARNING: This version of JDBCAppender
|
||||
is very likely to be completely replaced in the future. Moreoever,
|
||||
it does not log exceptions</font></b>.
|
||||
|
||||
<p>Each append call adds to an <code>ArrayList</code> buffer. When
|
||||
the buffer is filled each log event is placed in a sql statement
|
||||
(configurable) and executed.
|
||||
|
||||
<b>BufferSize</b>, <b>db URL</b>, <b>User</b>, & <b>Password</b> are
|
||||
configurable options in the standard log4j ways.
|
||||
|
||||
<p>The <code>setSql(String sql)</code> sets the SQL statement to be
|
||||
used for logging -- this statement is sent to a
|
||||
<code>PatternLayout</code> (either created automaticly by the
|
||||
appender or added by the user). Therefore by default all the
|
||||
conversion patterns in <code>PatternLayout</code> can be used
|
||||
inside of the statement. (see the test cases for examples)
|
||||
|
||||
<p>Overriding the {@link #getLogStatement} method allows more
|
||||
explicit control of the statement used for logging.
|
||||
|
||||
<p>For use as a base class:
|
||||
|
||||
<ul>
|
||||
|
||||
<li>Override <code>getConnection()</code> to pass any connection
|
||||
you want. Typically this is used to enable application wide
|
||||
connection pooling.
|
||||
|
||||
<li>Override <code>closeConnection(Connection con)</code> -- if
|
||||
you override getConnection make sure to implement
|
||||
<code>closeConnection</code> to handle the connection you
|
||||
generated. Typically this would return the connection to the
|
||||
pool it came from.
|
||||
|
||||
<li>Override <code>getLogStatement(LoggingEvent event)</code> to
|
||||
produce specialized or dynamic statements. The default uses the
|
||||
sql option value.
|
||||
|
||||
</ul>
|
||||
|
||||
@author Kevin Steppe (<A HREF="mailto:ksteppe@pacbell.net">ksteppe@pacbell.net</A>)
|
||||
|
||||
*/
|
||||
public class JDBCAppender extends org.apache.log4j.AppenderSkeleton
|
||||
implements org.apache.log4j.Appender {
|
||||
|
||||
/**
|
||||
* URL of the DB for default connection handling
|
||||
*/
|
||||
protected String databaseURL = "jdbc:odbc:myDB";
|
||||
|
||||
/**
|
||||
* User to connect as for default connection handling
|
||||
*/
|
||||
protected String databaseUser = "me";
|
||||
|
||||
/**
|
||||
* User to use for default connection handling
|
||||
*/
|
||||
protected String databasePassword = "mypassword";
|
||||
|
||||
/**
|
||||
* Connection used by default. The connection is opened the first time it
|
||||
* is needed and then held open until the appender is closed (usually at
|
||||
* garbage collection). This behavior is best modified by creating a
|
||||
* sub-class and overriding the <code>getConnection</code> and
|
||||
* <code>closeConnection</code> methods.
|
||||
*/
|
||||
protected Connection connection = null;
|
||||
|
||||
/**
|
||||
* Stores the string given to the pattern layout for conversion into a SQL
|
||||
* statement, eg: insert into LogTable (Thread, Class, Message) values
|
||||
* ("%t", "%c", "%m").
|
||||
*
|
||||
* Be careful of quotes in your messages!
|
||||
*
|
||||
* Also see PatternLayout.
|
||||
*/
|
||||
protected String sqlStatement = "";
|
||||
|
||||
/**
|
||||
* size of LoggingEvent buffer before writting to the database.
|
||||
* Default is 1.
|
||||
*/
|
||||
protected int bufferSize = 1;
|
||||
|
||||
/**
|
||||
* ArrayList holding the buffer of Logging Events.
|
||||
*/
|
||||
protected ArrayList buffer;
|
||||
|
||||
/**
|
||||
* Helper object for clearing out the buffer
|
||||
*/
|
||||
protected ArrayList removes;
|
||||
|
||||
private boolean locationInfo = false;
|
||||
|
||||
public JDBCAppender() {
|
||||
super();
|
||||
buffer = new ArrayList(bufferSize);
|
||||
removes = new ArrayList(bufferSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the location of the logging request call
|
||||
* should be captured.
|
||||
*
|
||||
* @since 1.2.16
|
||||
* @return the current value of the <b>LocationInfo</b> option.
|
||||
*/
|
||||
public boolean getLocationInfo() {
|
||||
return locationInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* The <b>LocationInfo</b> option takes a boolean value. By default, it is
|
||||
* set to false which means there will be no effort to extract the location
|
||||
* information related to the event. As a result, the event that will be
|
||||
* ultimately logged will likely to contain the wrong location information
|
||||
* (if present in the log format).
|
||||
* <p/>
|
||||
* <p/>
|
||||
* Location information extraction is comparatively very slow and should be
|
||||
* avoided unless performance is not a concern.
|
||||
* </p>
|
||||
* @since 1.2.16
|
||||
* @param flag true if location information should be extracted.
|
||||
*/
|
||||
public void setLocationInfo(final boolean flag) {
|
||||
locationInfo = flag;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the event to the buffer. When full the buffer is flushed.
|
||||
*/
|
||||
public void append(LoggingEvent event) {
|
||||
event.getNDC();
|
||||
event.getThreadName();
|
||||
// Get a copy of this thread's MDC.
|
||||
event.getMDCCopy();
|
||||
if (locationInfo) {
|
||||
event.getLocationInformation();
|
||||
}
|
||||
event.getRenderedMessage();
|
||||
event.getThrowableStrRep();
|
||||
buffer.add(event);
|
||||
|
||||
if (buffer.size() >= bufferSize)
|
||||
flushBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* By default getLogStatement sends the event to the required Layout object.
|
||||
* The layout will format the given pattern into a workable SQL string.
|
||||
*
|
||||
* Overriding this provides direct access to the LoggingEvent
|
||||
* when constructing the logging statement.
|
||||
*
|
||||
*/
|
||||
protected String getLogStatement(LoggingEvent event) {
|
||||
return getLayout().format(event);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Override this to provide an alertnate method of getting
|
||||
* connections (such as caching). One method to fix this is to open
|
||||
* connections at the start of flushBuffer() and close them at the
|
||||
* end. I use a connection pool outside of JDBCAppender which is
|
||||
* accessed in an override of this method.
|
||||
* */
|
||||
protected void execute(String sql) throws SQLException {
|
||||
|
||||
Connection con = null;
|
||||
Statement stmt = null;
|
||||
|
||||
try {
|
||||
con = getConnection();
|
||||
|
||||
stmt = con.createStatement();
|
||||
stmt.executeUpdate(sql);
|
||||
} catch (SQLException e) {
|
||||
if (stmt != null)
|
||||
stmt.close();
|
||||
throw e;
|
||||
}
|
||||
stmt.close();
|
||||
closeConnection(con);
|
||||
|
||||
//System.out.println("Execute: " + sql);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Override this to return the connection to a pool, or to clean up the
|
||||
* resource.
|
||||
*
|
||||
* The default behavior holds a single connection open until the appender
|
||||
* is closed (typically when garbage collected).
|
||||
*/
|
||||
protected void closeConnection(Connection con) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this to link with your connection pooling system.
|
||||
*
|
||||
* By default this creates a single connection which is held open
|
||||
* until the object is garbage collected.
|
||||
*/
|
||||
protected Connection getConnection() throws SQLException {
|
||||
if (!DriverManager.getDrivers().hasMoreElements())
|
||||
setDriver("sun.jdbc.odbc.JdbcOdbcDriver");
|
||||
|
||||
if (connection == null) {
|
||||
connection = DriverManager.getConnection(databaseURL, databaseUser,
|
||||
databasePassword);
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the appender, flushing the buffer first then closing the default
|
||||
* connection if it is open.
|
||||
*/
|
||||
public void close()
|
||||
{
|
||||
flushBuffer();
|
||||
|
||||
try {
|
||||
if (connection != null && !connection.isClosed())
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
errorHandler.error("Error closing connection", e, ErrorCode.GENERIC_FAILURE);
|
||||
}
|
||||
this.closed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* loops through the buffer of LoggingEvents, gets a
|
||||
* sql string from getLogStatement() and sends it to execute().
|
||||
* Errors are sent to the errorHandler.
|
||||
*
|
||||
* If a statement fails the LoggingEvent stays in the buffer!
|
||||
*/
|
||||
public void flushBuffer() {
|
||||
//Do the actual logging
|
||||
removes.ensureCapacity(buffer.size());
|
||||
for (Iterator i = buffer.iterator(); i.hasNext();) {
|
||||
try {
|
||||
LoggingEvent logEvent = (LoggingEvent)i.next();
|
||||
String sql = getLogStatement(logEvent);
|
||||
execute(sql);
|
||||
removes.add(logEvent);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
errorHandler.error("Failed to excute sql", e,
|
||||
ErrorCode.FLUSH_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// remove from the buffer any events that were reported
|
||||
buffer.removeAll(removes);
|
||||
|
||||
// clear the buffer of reported events
|
||||
removes.clear();
|
||||
}
|
||||
|
||||
|
||||
/** closes the appender before disposal */
|
||||
public void finalize() {
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* JDBCAppender requires a layout.
|
||||
* */
|
||||
public boolean requiresLayout() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void setSql(String s) {
|
||||
sqlStatement = s;
|
||||
if (getLayout() == null) {
|
||||
this.setLayout(new PatternLayout(s));
|
||||
}
|
||||
else {
|
||||
((PatternLayout)getLayout()).setConversionPattern(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns pre-formated statement eg: insert into LogTable (msg) values ("%m")
|
||||
*/
|
||||
public String getSql() {
|
||||
return sqlStatement;
|
||||
}
|
||||
|
||||
|
||||
public void setUser(String user) {
|
||||
databaseUser = user;
|
||||
}
|
||||
|
||||
|
||||
public void setURL(String url) {
|
||||
databaseURL = url;
|
||||
}
|
||||
|
||||
|
||||
public void setPassword(String password) {
|
||||
databasePassword = password;
|
||||
}
|
||||
|
||||
|
||||
public void setBufferSize(int newBufferSize) {
|
||||
bufferSize = newBufferSize;
|
||||
buffer.ensureCapacity(bufferSize);
|
||||
removes.ensureCapacity(bufferSize);
|
||||
}
|
||||
|
||||
|
||||
public String getUser() {
|
||||
return databaseUser;
|
||||
}
|
||||
|
||||
|
||||
public String getURL() {
|
||||
return databaseURL;
|
||||
}
|
||||
|
||||
|
||||
public String getPassword() {
|
||||
return databasePassword;
|
||||
}
|
||||
|
||||
|
||||
public int getBufferSize() {
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensures that the given driver class has been loaded for sql connection
|
||||
* creation.
|
||||
*/
|
||||
public void setDriver(String driverClass) {
|
||||
try {
|
||||
Class.forName(driverClass);
|
||||
} catch (Exception e) {
|
||||
errorHandler.error("Failed to load driver", e,
|
||||
ErrorCode.GENERIC_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
java/src/org/apache/log4j/jdbc/package.html
Normal file
23
java/src/org/apache/log4j/jdbc/package.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You 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.
|
||||
|
||||
-->
|
||||
<html>
|
||||
|
||||
<body>
|
||||
The JDBCAppender provides for sending log events to a database.
|
||||
</body>
|
||||
</html>
|
||||
187
java/src/org/apache/log4j/jmx/AbstractDynamicMBean.java
Normal file
187
java/src/org/apache/log4j/jmx/AbstractDynamicMBean.java
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.jmx;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.DynamicMBean;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.JMException;
|
||||
import javax.management.MBeanRegistration;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.NotCompliantMBeanException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.Appender;
|
||||
|
||||
public abstract class AbstractDynamicMBean implements DynamicMBean,
|
||||
MBeanRegistration {
|
||||
|
||||
String dClassName;
|
||||
MBeanServer server;
|
||||
private final Vector mbeanList = new Vector();
|
||||
|
||||
/**
|
||||
* Get MBean name.
|
||||
* @param appender appender, may not be null.
|
||||
* @return name.
|
||||
* @since 1.2.16
|
||||
*/
|
||||
static protected String getAppenderName(final Appender appender){
|
||||
String name = appender.getName();
|
||||
if (name == null || name.trim().length() == 0) {
|
||||
// try to get some form of a name, because null is not allowed (exception), and empty string certainly isn't useful in JMX..
|
||||
name = appender.toString();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enables the to get the values of several attributes of the Dynamic MBean.
|
||||
*/
|
||||
public
|
||||
AttributeList getAttributes(String[] attributeNames) {
|
||||
|
||||
// Check attributeNames is not null to avoid NullPointerException later on
|
||||
if (attributeNames == null) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("attributeNames[] cannot be null"),
|
||||
"Cannot invoke a getter of " + dClassName);
|
||||
}
|
||||
|
||||
AttributeList resultList = new AttributeList();
|
||||
|
||||
// if attributeNames is empty, return an empty result list
|
||||
if (attributeNames.length == 0)
|
||||
return resultList;
|
||||
|
||||
// build the result attribute list
|
||||
for (int i=0 ; i<attributeNames.length ; i++){
|
||||
try {
|
||||
Object value = getAttribute((String) attributeNames[i]);
|
||||
resultList.add(new Attribute(attributeNames[i],value));
|
||||
} catch (JMException e) {
|
||||
e.printStackTrace();
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return(resultList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the values of several attributes of the Dynamic MBean, and returns the
|
||||
* list of attributes that have been set.
|
||||
*/
|
||||
public AttributeList setAttributes(AttributeList attributes) {
|
||||
|
||||
// Check attributes is not null to avoid NullPointerException later on
|
||||
if (attributes == null) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("AttributeList attributes cannot be null"),
|
||||
"Cannot invoke a setter of " + dClassName);
|
||||
}
|
||||
AttributeList resultList = new AttributeList();
|
||||
|
||||
// if attributeNames is empty, nothing more to do
|
||||
if (attributes.isEmpty())
|
||||
return resultList;
|
||||
|
||||
// for each attribute, try to set it and add to the result list if successfull
|
||||
for (Iterator i = attributes.iterator(); i.hasNext();) {
|
||||
Attribute attr = (Attribute) i.next();
|
||||
try {
|
||||
setAttribute(attr);
|
||||
String name = attr.getName();
|
||||
Object value = getAttribute(name);
|
||||
resultList.add(new Attribute(name,value));
|
||||
} catch(JMException e) {
|
||||
e.printStackTrace();
|
||||
} catch(RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return(resultList);
|
||||
}
|
||||
|
||||
protected
|
||||
abstract
|
||||
Logger getLogger();
|
||||
|
||||
public
|
||||
void postDeregister() {
|
||||
getLogger().debug("postDeregister is called.");
|
||||
}
|
||||
|
||||
public
|
||||
void postRegister(java.lang.Boolean registrationDone) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
public
|
||||
ObjectName preRegister(MBeanServer server, ObjectName name) {
|
||||
getLogger().debug("preRegister called. Server="+server+ ", name="+name);
|
||||
this.server = server;
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* Registers MBean instance in the attached server. Must <em>NOT</em>
|
||||
* be called before registration of this instance.
|
||||
*/
|
||||
protected
|
||||
void registerMBean(Object mbean, ObjectName objectName)
|
||||
throws InstanceAlreadyExistsException, MBeanRegistrationException,
|
||||
NotCompliantMBeanException {
|
||||
server.registerMBean(mbean, objectName);
|
||||
mbeanList.add(objectName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs cleanup for deregistering this MBean. Default implementation
|
||||
* unregisters MBean instances which are registered using
|
||||
* {@link #registerMBean(Object mbean, ObjectName objectName)}.
|
||||
*/
|
||||
public
|
||||
void preDeregister() {
|
||||
getLogger().debug("preDeregister called.");
|
||||
|
||||
Enumeration iterator = mbeanList.elements();
|
||||
while (iterator.hasMoreElements()) {
|
||||
ObjectName name = (ObjectName) iterator.nextElement();
|
||||
try {
|
||||
server.unregisterMBean(name);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
getLogger().warn("Missing MBean " + name.getCanonicalName());
|
||||
} catch (MBeanRegistrationException e) {
|
||||
getLogger().warn("Failed unregistering " + name.getCanonicalName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
131
java/src/org/apache/log4j/jmx/Agent.java
Normal file
131
java/src/org/apache/log4j/jmx/Agent.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.jmx;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import javax.management.JMException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerFactory;
|
||||
import javax.management.ObjectName;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
|
||||
/**
|
||||
* Manages an instance of com.sun.jdmk.comm.HtmlAdapterServer which
|
||||
* was provided for demonstration purposes in the
|
||||
* Java Management Extensions Reference Implementation 1.2.1.
|
||||
* This class is provided to maintain compatibility with earlier
|
||||
* versions of log4j and use in new code is discouraged.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public class Agent {
|
||||
|
||||
/**
|
||||
* Diagnostic logger.
|
||||
* @deprecated
|
||||
*/
|
||||
static Logger log = Logger.getLogger(Agent.class);
|
||||
|
||||
/**
|
||||
* Create new instance.
|
||||
* @deprecated
|
||||
*/
|
||||
public Agent() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of com.sun.jdmk.comm.HtmlAdapterServer
|
||||
* using reflection.
|
||||
*
|
||||
* @since 1.2.16
|
||||
* @return new instance.
|
||||
*/
|
||||
private static Object createServer() {
|
||||
Object newInstance = null;
|
||||
try {
|
||||
newInstance = Class.forName(
|
||||
"com.sun.jdmk.comm.HtmlAdapterServer").newInstance();
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new RuntimeException(ex.toString());
|
||||
} catch (InstantiationException ex) {
|
||||
throw new RuntimeException(ex.toString());
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new RuntimeException(ex.toString());
|
||||
}
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes HtmlAdapterServer.start() using reflection.
|
||||
*
|
||||
* @since 1.2.16
|
||||
* @param server instance of com.sun.jdmk.comm.HtmlAdapterServer.
|
||||
*/
|
||||
private static void startServer(final Object server) {
|
||||
try {
|
||||
server.getClass().getMethod("start", new Class[0]).
|
||||
invoke(server, new Object[0]);
|
||||
} catch(InvocationTargetException ex) {
|
||||
Throwable cause = ex.getTargetException();
|
||||
if (cause instanceof RuntimeException) {
|
||||
throw (RuntimeException) cause;
|
||||
} else if (cause != null) {
|
||||
if (cause instanceof InterruptedException
|
||||
|| cause instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
throw new RuntimeException(cause.toString());
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
} catch(NoSuchMethodException ex) {
|
||||
throw new RuntimeException(ex.toString());
|
||||
} catch(IllegalAccessException ex) {
|
||||
throw new RuntimeException(ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts instance of HtmlAdapterServer.
|
||||
* @deprecated
|
||||
*/
|
||||
public void start() {
|
||||
|
||||
MBeanServer server = MBeanServerFactory.createMBeanServer();
|
||||
Object html = createServer();
|
||||
|
||||
try {
|
||||
log.info("Registering HtmlAdaptorServer instance.");
|
||||
server.registerMBean(html, new ObjectName("Adaptor:name=html,port=8082"));
|
||||
log.info("Registering HierarchyDynamicMBean instance.");
|
||||
HierarchyDynamicMBean hdm = new HierarchyDynamicMBean();
|
||||
server.registerMBean(hdm, new ObjectName("log4j:hiearchy=default"));
|
||||
} catch(JMException e) {
|
||||
log.error("Problem while registering MBeans instances.", e);
|
||||
return;
|
||||
} catch(RuntimeException e) {
|
||||
log.error("Problem while registering MBeans instances.", e);
|
||||
return;
|
||||
}
|
||||
startServer(html);
|
||||
}
|
||||
}
|
||||
346
java/src/org/apache/log4j/jmx/AppenderDynamicMBean.java
Normal file
346
java/src/org/apache/log4j/jmx/AppenderDynamicMBean.java
Normal file
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.jmx;
|
||||
|
||||
import org.apache.log4j.Appender;
|
||||
import org.apache.log4j.Layout;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.Priority;
|
||||
import org.apache.log4j.helpers.OptionConverter;
|
||||
import org.apache.log4j.spi.OptionHandler;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.JMException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
public class AppenderDynamicMBean extends AbstractDynamicMBean {
|
||||
|
||||
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
|
||||
private Vector dAttributes = new Vector();
|
||||
private String dClassName = this.getClass().getName();
|
||||
|
||||
private Hashtable dynamicProps = new Hashtable(5);
|
||||
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[2];
|
||||
private String dDescription =
|
||||
"This MBean acts as a management facade for log4j appenders.";
|
||||
|
||||
// This category instance is for logging.
|
||||
private static Logger cat = Logger.getLogger(AppenderDynamicMBean.class);
|
||||
|
||||
// We wrap this appender instance.
|
||||
private Appender appender;
|
||||
|
||||
public AppenderDynamicMBean(Appender appender) throws IntrospectionException {
|
||||
this.appender = appender;
|
||||
buildDynamicMBeanInfo();
|
||||
}
|
||||
|
||||
private
|
||||
void buildDynamicMBeanInfo() throws IntrospectionException {
|
||||
Constructor[] constructors = this.getClass().getConstructors();
|
||||
dConstructors[0] = new MBeanConstructorInfo(
|
||||
"AppenderDynamicMBean(): Constructs a AppenderDynamicMBean instance",
|
||||
constructors[0]);
|
||||
|
||||
|
||||
BeanInfo bi = Introspector.getBeanInfo(appender.getClass());
|
||||
PropertyDescriptor[] pd = bi.getPropertyDescriptors();
|
||||
|
||||
int size = pd.length;
|
||||
|
||||
for(int i = 0; i < size; i++) {
|
||||
String name = pd[i].getName();
|
||||
Method readMethod = pd[i].getReadMethod();
|
||||
Method writeMethod = pd[i].getWriteMethod();
|
||||
if(readMethod != null) {
|
||||
Class returnClass = readMethod.getReturnType();
|
||||
if(isSupportedType(returnClass)) {
|
||||
String returnClassName;
|
||||
if(returnClass.isAssignableFrom(Priority.class)) {
|
||||
returnClassName = "java.lang.String";
|
||||
} else {
|
||||
returnClassName = returnClass.getName();
|
||||
}
|
||||
|
||||
dAttributes.add(new MBeanAttributeInfo(name,
|
||||
returnClassName,
|
||||
"Dynamic",
|
||||
true,
|
||||
writeMethod != null,
|
||||
false));
|
||||
dynamicProps.put(name, new MethodUnion(readMethod, writeMethod));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MBeanParameterInfo[] params = new MBeanParameterInfo[0];
|
||||
|
||||
dOperations[0] = new MBeanOperationInfo("activateOptions",
|
||||
"activateOptions(): add an appender",
|
||||
params,
|
||||
"void",
|
||||
MBeanOperationInfo.ACTION);
|
||||
|
||||
params = new MBeanParameterInfo[1];
|
||||
params[0] = new MBeanParameterInfo("layout class", "java.lang.String",
|
||||
"layout class");
|
||||
|
||||
dOperations[1] = new MBeanOperationInfo("setLayout",
|
||||
"setLayout(): add a layout",
|
||||
params,
|
||||
"void",
|
||||
MBeanOperationInfo.ACTION);
|
||||
}
|
||||
|
||||
private
|
||||
boolean isSupportedType(Class clazz) {
|
||||
if(clazz.isPrimitive()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(clazz == String.class) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if(clazz.isAssignableFrom(Priority.class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public
|
||||
MBeanInfo getMBeanInfo() {
|
||||
cat.debug("getMBeanInfo called.");
|
||||
|
||||
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
|
||||
dAttributes.toArray(attribs);
|
||||
|
||||
return new MBeanInfo(dClassName,
|
||||
dDescription,
|
||||
attribs,
|
||||
dConstructors,
|
||||
dOperations,
|
||||
new MBeanNotificationInfo[0]);
|
||||
}
|
||||
|
||||
public
|
||||
Object invoke(String operationName, Object params[], String signature[])
|
||||
throws MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
if(operationName.equals("activateOptions") &&
|
||||
appender instanceof OptionHandler) {
|
||||
OptionHandler oh = (OptionHandler) appender;
|
||||
oh.activateOptions();
|
||||
return "Options activated.";
|
||||
} else if (operationName.equals("setLayout")) {
|
||||
Layout layout = (Layout) OptionConverter.instantiateByClassName((String)
|
||||
params[0],
|
||||
Layout.class,
|
||||
null);
|
||||
appender.setLayout(layout);
|
||||
registerLayoutMBean(layout);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void registerLayoutMBean(Layout layout) {
|
||||
if(layout == null)
|
||||
return;
|
||||
|
||||
String name = getAppenderName(appender)+",layout="+layout.getClass().getName();
|
||||
cat.debug("Adding LayoutMBean:"+name);
|
||||
ObjectName objectName = null;
|
||||
try {
|
||||
LayoutDynamicMBean appenderMBean = new LayoutDynamicMBean(layout);
|
||||
objectName = new ObjectName("log4j:appender="+name);
|
||||
if (!server.isRegistered(objectName)) {
|
||||
registerMBean(appenderMBean, objectName);
|
||||
dAttributes.add(new MBeanAttributeInfo("appender=" + name, "javax.management.ObjectName",
|
||||
"The " + name + " layout.", true, true, false));
|
||||
}
|
||||
|
||||
} catch(JMException e) {
|
||||
cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
|
||||
} catch(java.beans.IntrospectionException e) {
|
||||
cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
|
||||
} catch(RuntimeException e) {
|
||||
cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected
|
||||
Logger getLogger() {
|
||||
return cat;
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
Object getAttribute(String attributeName) throws AttributeNotFoundException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
// Check attributeName is not null to avoid NullPointerException later on
|
||||
if (attributeName == null) {
|
||||
throw new RuntimeOperationsException(new IllegalArgumentException(
|
||||
"Attribute name cannot be null"),
|
||||
"Cannot invoke a getter of " + dClassName + " with null attribute name");
|
||||
}
|
||||
|
||||
cat.debug("getAttribute called with ["+attributeName+"].");
|
||||
if(attributeName.startsWith("appender="+appender.getName()+",layout")) {
|
||||
try {
|
||||
return new ObjectName("log4j:"+attributeName );
|
||||
} catch(MalformedObjectNameException e) {
|
||||
cat.error("attributeName", e);
|
||||
} catch(RuntimeException e) {
|
||||
cat.error("attributeName", e);
|
||||
}
|
||||
}
|
||||
|
||||
MethodUnion mu = (MethodUnion) dynamicProps.get(attributeName);
|
||||
|
||||
//cat.debug("----name="+attributeName+", b="+b);
|
||||
|
||||
if(mu != null && mu.readMethod != null) {
|
||||
try {
|
||||
return mu.readMethod.invoke(appender, null);
|
||||
} catch(IllegalAccessException e) {
|
||||
return null;
|
||||
} catch(InvocationTargetException e) {
|
||||
if (e.getTargetException() instanceof InterruptedException
|
||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return null;
|
||||
} catch(RuntimeException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// If attributeName has not been recognized throw an AttributeNotFoundException
|
||||
throw(new AttributeNotFoundException("Cannot find " + attributeName +
|
||||
" attribute in " + dClassName));
|
||||
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
|
||||
InvalidAttributeValueException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
// Check attribute is not null to avoid NullPointerException later on
|
||||
if (attribute == null) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("Attribute cannot be null"),
|
||||
"Cannot invoke a setter of " + dClassName +
|
||||
" with null attribute");
|
||||
}
|
||||
String name = attribute.getName();
|
||||
Object value = attribute.getValue();
|
||||
|
||||
if (name == null) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("Attribute name cannot be null"),
|
||||
"Cannot invoke the setter of "+dClassName+
|
||||
" with null attribute name");
|
||||
}
|
||||
|
||||
|
||||
|
||||
MethodUnion mu = (MethodUnion) dynamicProps.get(name);
|
||||
|
||||
if(mu != null && mu.writeMethod != null) {
|
||||
Object[] o = new Object[1];
|
||||
|
||||
Class[] params = mu.writeMethod.getParameterTypes();
|
||||
if(params[0] == org.apache.log4j.Priority.class) {
|
||||
value = OptionConverter.toLevel((String) value,
|
||||
(Level) getAttribute(name));
|
||||
}
|
||||
o[0] = value;
|
||||
|
||||
try {
|
||||
mu.writeMethod.invoke(appender, o);
|
||||
|
||||
} catch(InvocationTargetException e) {
|
||||
if (e.getTargetException() instanceof InterruptedException
|
||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
cat.error("FIXME", e);
|
||||
} catch(IllegalAccessException e) {
|
||||
cat.error("FIXME", e);
|
||||
} catch(RuntimeException e) {
|
||||
cat.error("FIXME", e);
|
||||
}
|
||||
} else if(name.endsWith(".layout")) {
|
||||
|
||||
} else {
|
||||
throw(new AttributeNotFoundException("Attribute " + name +
|
||||
" not found in " +
|
||||
this.getClass().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
ObjectName preRegister(MBeanServer server, ObjectName name) {
|
||||
cat.debug("preRegister called. Server="+server+ ", name="+name);
|
||||
this.server = server;
|
||||
registerLayoutMBean(appender.getLayout());
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
302
java/src/org/apache/log4j/jmx/HierarchyDynamicMBean.java
Normal file
302
java/src/org/apache/log4j/jmx/HierarchyDynamicMBean.java
Normal file
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.jmx;
|
||||
|
||||
|
||||
import org.apache.log4j.Appender;
|
||||
import org.apache.log4j.Category;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.LogManager;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.helpers.OptionConverter;
|
||||
import org.apache.log4j.spi.HierarchyEventListener;
|
||||
import org.apache.log4j.spi.LoggerRepository;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.JMException;
|
||||
import javax.management.ListenerNotFoundException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationBroadcaster;
|
||||
import javax.management.NotificationBroadcasterSupport;
|
||||
import javax.management.NotificationFilter;
|
||||
import javax.management.NotificationFilterSupport;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Vector;
|
||||
|
||||
public class HierarchyDynamicMBean extends AbstractDynamicMBean
|
||||
implements HierarchyEventListener,
|
||||
NotificationBroadcaster {
|
||||
|
||||
static final String ADD_APPENDER = "addAppender.";
|
||||
static final String THRESHOLD = "threshold";
|
||||
|
||||
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
|
||||
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
|
||||
|
||||
private Vector vAttributes = new Vector();
|
||||
private String dClassName = this.getClass().getName();
|
||||
private String dDescription =
|
||||
"This MBean acts as a management facade for org.apache.log4j.Hierarchy.";
|
||||
|
||||
private NotificationBroadcasterSupport nbs = new NotificationBroadcasterSupport();
|
||||
|
||||
|
||||
private LoggerRepository hierarchy;
|
||||
|
||||
private static Logger log = Logger.getLogger(HierarchyDynamicMBean.class);
|
||||
|
||||
public HierarchyDynamicMBean() {
|
||||
hierarchy = LogManager.getLoggerRepository();
|
||||
buildDynamicMBeanInfo();
|
||||
}
|
||||
|
||||
private
|
||||
void buildDynamicMBeanInfo() {
|
||||
Constructor[] constructors = this.getClass().getConstructors();
|
||||
dConstructors[0] = new MBeanConstructorInfo(
|
||||
"HierarchyDynamicMBean(): Constructs a HierarchyDynamicMBean instance",
|
||||
constructors[0]);
|
||||
|
||||
vAttributes.add(new MBeanAttributeInfo(THRESHOLD,
|
||||
"java.lang.String",
|
||||
"The \"threshold\" state of the hiearchy.",
|
||||
true,
|
||||
true,
|
||||
false));
|
||||
|
||||
MBeanParameterInfo[] params = new MBeanParameterInfo[1];
|
||||
params[0] = new MBeanParameterInfo("name", "java.lang.String",
|
||||
"Create a logger MBean" );
|
||||
dOperations[0] = new MBeanOperationInfo("addLoggerMBean",
|
||||
"addLoggerMBean(): add a loggerMBean",
|
||||
params ,
|
||||
"javax.management.ObjectName",
|
||||
MBeanOperationInfo.ACTION);
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
ObjectName addLoggerMBean(String name) {
|
||||
Logger cat = LogManager.exists(name);
|
||||
|
||||
if(cat != null) {
|
||||
return addLoggerMBean(cat);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ObjectName addLoggerMBean(Logger logger) {
|
||||
String name = logger.getName();
|
||||
ObjectName objectName = null;
|
||||
try {
|
||||
LoggerDynamicMBean loggerMBean = new LoggerDynamicMBean(logger);
|
||||
objectName = new ObjectName("log4j", "logger", name);
|
||||
|
||||
if (!server.isRegistered(objectName)) {
|
||||
registerMBean(loggerMBean, objectName);
|
||||
NotificationFilterSupport nfs = new NotificationFilterSupport();
|
||||
nfs.enableType(ADD_APPENDER + logger.getName());
|
||||
log.debug("---Adding logger [" + name + "] as listener.");
|
||||
nbs.addNotificationListener(loggerMBean, nfs, null);
|
||||
vAttributes.add(new MBeanAttributeInfo("logger=" + name, "javax.management.ObjectName",
|
||||
"The " + name + " logger.", true, true, // this makes the object
|
||||
// clickable
|
||||
false));
|
||||
|
||||
}
|
||||
|
||||
} catch(JMException e) {
|
||||
log.error("Could not add loggerMBean for ["+name+"].", e);
|
||||
} catch(RuntimeException e) {
|
||||
log.error("Could not add loggerMBean for ["+name+"].", e);
|
||||
}
|
||||
return objectName;
|
||||
}
|
||||
|
||||
public
|
||||
void addNotificationListener(NotificationListener listener,
|
||||
NotificationFilter filter,
|
||||
java.lang.Object handback) {
|
||||
nbs.addNotificationListener(listener, filter, handback);
|
||||
}
|
||||
|
||||
protected
|
||||
Logger getLogger() {
|
||||
return log;
|
||||
}
|
||||
|
||||
public
|
||||
MBeanInfo getMBeanInfo() {
|
||||
//cat.debug("getMBeanInfo called.");
|
||||
|
||||
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[vAttributes.size()];
|
||||
vAttributes.toArray(attribs);
|
||||
|
||||
return new MBeanInfo(dClassName,
|
||||
dDescription,
|
||||
attribs,
|
||||
dConstructors,
|
||||
dOperations,
|
||||
new MBeanNotificationInfo[0]);
|
||||
}
|
||||
|
||||
public
|
||||
MBeanNotificationInfo[] getNotificationInfo(){
|
||||
return nbs.getNotificationInfo();
|
||||
}
|
||||
|
||||
public
|
||||
Object invoke(String operationName,
|
||||
Object params[],
|
||||
String signature[]) throws MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
if (operationName == null) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("Operation name cannot be null"),
|
||||
"Cannot invoke a null operation in " + dClassName);
|
||||
}
|
||||
// Check for a recognized operation name and call the corresponding operation
|
||||
|
||||
if(operationName.equals("addLoggerMBean")) {
|
||||
return addLoggerMBean((String)params[0]);
|
||||
} else {
|
||||
throw new ReflectionException(
|
||||
new NoSuchMethodException(operationName),
|
||||
"Cannot find the operation " + operationName + " in " + dClassName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
Object getAttribute(String attributeName) throws AttributeNotFoundException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
// Check attributeName is not null to avoid NullPointerException later on
|
||||
if (attributeName == null) {
|
||||
throw new RuntimeOperationsException(new IllegalArgumentException(
|
||||
"Attribute name cannot be null"),
|
||||
"Cannot invoke a getter of " + dClassName + " with null attribute name");
|
||||
}
|
||||
|
||||
log.debug("Called getAttribute with ["+attributeName+"].");
|
||||
|
||||
// Check for a recognized attributeName and call the corresponding getter
|
||||
if (attributeName.equals(THRESHOLD)) {
|
||||
return hierarchy.getThreshold();
|
||||
} else if(attributeName.startsWith("logger")) {
|
||||
int k = attributeName.indexOf("%3D");
|
||||
String val = attributeName;
|
||||
if(k > 0) {
|
||||
val = attributeName.substring(0, k)+'='+ attributeName.substring(k+3);
|
||||
}
|
||||
try {
|
||||
return new ObjectName("log4j:"+val);
|
||||
} catch(JMException e) {
|
||||
log.error("Could not create ObjectName" + val);
|
||||
} catch(RuntimeException e) {
|
||||
log.error("Could not create ObjectName" + val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// If attributeName has not been recognized throw an AttributeNotFoundException
|
||||
throw(new AttributeNotFoundException("Cannot find " + attributeName +
|
||||
" attribute in " + dClassName));
|
||||
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
void addAppenderEvent(Category logger, Appender appender) {
|
||||
log.debug("addAppenderEvent called: logger="+logger.getName()+
|
||||
", appender="+appender.getName());
|
||||
Notification n = new Notification(ADD_APPENDER+logger.getName(), this, 0);
|
||||
n.setUserData(appender);
|
||||
log.debug("sending notification.");
|
||||
nbs.sendNotification(n);
|
||||
}
|
||||
|
||||
public
|
||||
void removeAppenderEvent(Category cat, Appender appender) {
|
||||
log.debug("removeAppenderCalled: logger="+cat.getName()+
|
||||
", appender="+appender.getName());
|
||||
}
|
||||
|
||||
public
|
||||
void postRegister(java.lang.Boolean registrationDone) {
|
||||
log.debug("postRegister is called.");
|
||||
hierarchy.addHierarchyEventListener(this);
|
||||
Logger root = hierarchy.getRootLogger();
|
||||
addLoggerMBean(root);
|
||||
}
|
||||
|
||||
public
|
||||
void removeNotificationListener(NotificationListener listener)
|
||||
throws ListenerNotFoundException {
|
||||
nbs.removeNotificationListener(listener);
|
||||
}
|
||||
|
||||
public
|
||||
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
|
||||
InvalidAttributeValueException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
// Check attribute is not null to avoid NullPointerException later on
|
||||
if (attribute == null) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("Attribute cannot be null"),
|
||||
"Cannot invoke a setter of "+dClassName+" with null attribute");
|
||||
}
|
||||
String name = attribute.getName();
|
||||
Object value = attribute.getValue();
|
||||
|
||||
if (name == null) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("Attribute name cannot be null"),
|
||||
"Cannot invoke the setter of "+dClassName+
|
||||
" with null attribute name");
|
||||
}
|
||||
|
||||
if(name.equals(THRESHOLD)) {
|
||||
Level l = OptionConverter.toLevel((String) value,
|
||||
hierarchy.getThreshold());
|
||||
hierarchy.setThreshold(l);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
274
java/src/org/apache/log4j/jmx/LayoutDynamicMBean.java
Normal file
274
java/src/org/apache/log4j/jmx/LayoutDynamicMBean.java
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.jmx;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Layout;
|
||||
import org.apache.log4j.helpers.OptionConverter;
|
||||
import org.apache.log4j.spi.OptionHandler;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.Hashtable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.Attribute;
|
||||
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
|
||||
import java.beans.Introspector;
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
public class LayoutDynamicMBean extends AbstractDynamicMBean {
|
||||
|
||||
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
|
||||
private Vector dAttributes = new Vector();
|
||||
private String dClassName = this.getClass().getName();
|
||||
|
||||
private Hashtable dynamicProps = new Hashtable(5);
|
||||
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
|
||||
private String dDescription =
|
||||
"This MBean acts as a management facade for log4j layouts.";
|
||||
|
||||
// This category instance is for logging.
|
||||
private static Logger cat = Logger.getLogger(LayoutDynamicMBean.class);
|
||||
|
||||
// We wrap this layout instance.
|
||||
private Layout layout;
|
||||
|
||||
public LayoutDynamicMBean(Layout layout) throws IntrospectionException {
|
||||
this.layout = layout;
|
||||
buildDynamicMBeanInfo();
|
||||
}
|
||||
|
||||
private
|
||||
void buildDynamicMBeanInfo() throws IntrospectionException {
|
||||
Constructor[] constructors = this.getClass().getConstructors();
|
||||
dConstructors[0] = new MBeanConstructorInfo(
|
||||
"LayoutDynamicMBean(): Constructs a LayoutDynamicMBean instance",
|
||||
constructors[0]);
|
||||
|
||||
|
||||
BeanInfo bi = Introspector.getBeanInfo(layout.getClass());
|
||||
PropertyDescriptor[] pd = bi.getPropertyDescriptors();
|
||||
|
||||
int size = pd.length;
|
||||
|
||||
for(int i = 0; i < size; i++) {
|
||||
String name = pd[i].getName();
|
||||
Method readMethod = pd[i].getReadMethod();
|
||||
Method writeMethod = pd[i].getWriteMethod();
|
||||
if(readMethod != null) {
|
||||
Class returnClass = readMethod.getReturnType();
|
||||
if(isSupportedType(returnClass)) {
|
||||
String returnClassName;
|
||||
if(returnClass.isAssignableFrom(Level.class)) {
|
||||
returnClassName = "java.lang.String";
|
||||
} else {
|
||||
returnClassName = returnClass.getName();
|
||||
}
|
||||
|
||||
dAttributes.add(new MBeanAttributeInfo(name,
|
||||
returnClassName,
|
||||
"Dynamic",
|
||||
true,
|
||||
writeMethod != null,
|
||||
false));
|
||||
dynamicProps.put(name, new MethodUnion(readMethod, writeMethod));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MBeanParameterInfo[] params = new MBeanParameterInfo[0];
|
||||
|
||||
dOperations[0] = new MBeanOperationInfo("activateOptions",
|
||||
"activateOptions(): add an layout",
|
||||
params,
|
||||
"void",
|
||||
MBeanOperationInfo.ACTION);
|
||||
}
|
||||
|
||||
private
|
||||
boolean isSupportedType(Class clazz) {
|
||||
if(clazz.isPrimitive()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(clazz == String.class) {
|
||||
return true;
|
||||
}
|
||||
if(clazz.isAssignableFrom(Level.class)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public
|
||||
MBeanInfo getMBeanInfo() {
|
||||
cat.debug("getMBeanInfo called.");
|
||||
|
||||
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
|
||||
dAttributes.toArray(attribs);
|
||||
|
||||
return new MBeanInfo(dClassName,
|
||||
dDescription,
|
||||
attribs,
|
||||
dConstructors,
|
||||
dOperations,
|
||||
new MBeanNotificationInfo[0]);
|
||||
}
|
||||
|
||||
public
|
||||
Object invoke(String operationName, Object params[], String signature[])
|
||||
throws MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
if(operationName.equals("activateOptions") &&
|
||||
layout instanceof OptionHandler) {
|
||||
OptionHandler oh = (OptionHandler) layout;
|
||||
oh.activateOptions();
|
||||
return "Options activated.";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected
|
||||
Logger getLogger() {
|
||||
return cat;
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
Object getAttribute(String attributeName) throws AttributeNotFoundException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
// Check attributeName is not null to avoid NullPointerException later on
|
||||
if (attributeName == null) {
|
||||
throw new RuntimeOperationsException(new IllegalArgumentException(
|
||||
"Attribute name cannot be null"),
|
||||
"Cannot invoke a getter of " + dClassName + " with null attribute name");
|
||||
}
|
||||
|
||||
|
||||
MethodUnion mu = (MethodUnion) dynamicProps.get(attributeName);
|
||||
|
||||
cat.debug("----name="+attributeName+", mu="+mu);
|
||||
|
||||
if(mu != null && mu.readMethod != null) {
|
||||
try {
|
||||
return mu.readMethod.invoke(layout, null);
|
||||
} catch(InvocationTargetException e) {
|
||||
if (e.getTargetException() instanceof InterruptedException
|
||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return null;
|
||||
} catch(IllegalAccessException e) {
|
||||
return null;
|
||||
} catch(RuntimeException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// If attributeName has not been recognized throw an AttributeNotFoundException
|
||||
throw(new AttributeNotFoundException("Cannot find " + attributeName +
|
||||
" attribute in " + dClassName));
|
||||
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
|
||||
InvalidAttributeValueException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
// Check attribute is not null to avoid NullPointerException later on
|
||||
if (attribute == null) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("Attribute cannot be null"),
|
||||
"Cannot invoke a setter of " + dClassName +
|
||||
" with null attribute");
|
||||
}
|
||||
String name = attribute.getName();
|
||||
Object value = attribute.getValue();
|
||||
|
||||
if (name == null) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("Attribute name cannot be null"),
|
||||
"Cannot invoke the setter of "+dClassName+
|
||||
" with null attribute name");
|
||||
}
|
||||
|
||||
|
||||
|
||||
MethodUnion mu = (MethodUnion) dynamicProps.get(name);
|
||||
|
||||
if(mu != null && mu.writeMethod != null) {
|
||||
Object[] o = new Object[1];
|
||||
|
||||
Class[] params = mu.writeMethod.getParameterTypes();
|
||||
if(params[0] == org.apache.log4j.Priority.class) {
|
||||
value = OptionConverter.toLevel((String) value,
|
||||
(Level) getAttribute(name));
|
||||
}
|
||||
o[0] = value;
|
||||
|
||||
try {
|
||||
mu.writeMethod.invoke(layout, o);
|
||||
|
||||
} catch(InvocationTargetException e) {
|
||||
if (e.getTargetException() instanceof InterruptedException
|
||||
|| e.getTargetException() instanceof InterruptedIOException) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
cat.error("FIXME", e);
|
||||
} catch(IllegalAccessException e) {
|
||||
cat.error("FIXME", e);
|
||||
} catch(RuntimeException e) {
|
||||
cat.error("FIXME", e);
|
||||
}
|
||||
} else {
|
||||
throw(new AttributeNotFoundException("Attribute " + name +
|
||||
" not found in " +
|
||||
this.getClass().getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
282
java/src/org/apache/log4j/jmx/LoggerDynamicMBean.java
Normal file
282
java/src/org/apache/log4j/jmx/LoggerDynamicMBean.java
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.
|
||||
*/
|
||||
|
||||
package org.apache.log4j.jmx;
|
||||
|
||||
import org.apache.log4j.Appender;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.helpers.OptionConverter;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.JMException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanConstructorInfo;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanNotificationInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanParameterInfo;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.Notification;
|
||||
import javax.management.NotificationListener;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.RuntimeOperationsException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
public class LoggerDynamicMBean extends AbstractDynamicMBean
|
||||
implements NotificationListener {
|
||||
|
||||
private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
|
||||
private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
|
||||
|
||||
private Vector dAttributes = new Vector();
|
||||
private String dClassName = this.getClass().getName();
|
||||
|
||||
private String dDescription =
|
||||
"This MBean acts as a management facade for a org.apache.log4j.Logger instance.";
|
||||
|
||||
// This Logger instance is for logging.
|
||||
private static Logger cat = Logger.getLogger(LoggerDynamicMBean.class);
|
||||
|
||||
// We wrap this Logger instance.
|
||||
private Logger logger;
|
||||
|
||||
public LoggerDynamicMBean(Logger logger) {
|
||||
this.logger = logger;
|
||||
buildDynamicMBeanInfo();
|
||||
}
|
||||
|
||||
public
|
||||
void handleNotification(Notification notification, Object handback) {
|
||||
cat.debug("Received notification: "+notification.getType());
|
||||
registerAppenderMBean((Appender) notification.getUserData() );
|
||||
|
||||
|
||||
}
|
||||
|
||||
private
|
||||
void buildDynamicMBeanInfo() {
|
||||
Constructor[] constructors = this.getClass().getConstructors();
|
||||
dConstructors[0] = new MBeanConstructorInfo(
|
||||
"HierarchyDynamicMBean(): Constructs a HierarchyDynamicMBean instance",
|
||||
constructors[0]);
|
||||
|
||||
dAttributes.add(new MBeanAttributeInfo("name",
|
||||
"java.lang.String",
|
||||
"The name of this Logger.",
|
||||
true,
|
||||
false,
|
||||
false));
|
||||
|
||||
dAttributes.add(new MBeanAttributeInfo("priority",
|
||||
"java.lang.String",
|
||||
"The priority of this logger.",
|
||||
true,
|
||||
true,
|
||||
false));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
MBeanParameterInfo[] params = new MBeanParameterInfo[2];
|
||||
params[0] = new MBeanParameterInfo("class name", "java.lang.String",
|
||||
"add an appender to this logger");
|
||||
params[1] = new MBeanParameterInfo("appender name", "java.lang.String",
|
||||
"name of the appender");
|
||||
|
||||
dOperations[0] = new MBeanOperationInfo("addAppender",
|
||||
"addAppender(): add an appender",
|
||||
params,
|
||||
"void",
|
||||
MBeanOperationInfo.ACTION);
|
||||
}
|
||||
|
||||
protected
|
||||
Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
MBeanInfo getMBeanInfo() {
|
||||
//cat.debug("getMBeanInfo called.");
|
||||
|
||||
MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
|
||||
dAttributes.toArray(attribs);
|
||||
|
||||
MBeanInfo mb = new MBeanInfo(dClassName,
|
||||
dDescription,
|
||||
attribs,
|
||||
dConstructors,
|
||||
dOperations,
|
||||
new MBeanNotificationInfo[0]);
|
||||
//cat.debug("getMBeanInfo exit.");
|
||||
return mb;
|
||||
}
|
||||
|
||||
public
|
||||
Object invoke(String operationName, Object params[], String signature[])
|
||||
throws MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
if(operationName.equals("addAppender")) {
|
||||
addAppender((String) params[0], (String) params[1]);
|
||||
return "Hello world.";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
Object getAttribute(String attributeName) throws AttributeNotFoundException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
// Check attributeName is not null to avoid NullPointerException later on
|
||||
if (attributeName == null) {
|
||||
throw new RuntimeOperationsException(new IllegalArgumentException(
|
||||
"Attribute name cannot be null"),
|
||||
"Cannot invoke a getter of " + dClassName + " with null attribute name");
|
||||
}
|
||||
|
||||
// Check for a recognized attributeName and call the corresponding getter
|
||||
if (attributeName.equals("name")) {
|
||||
return logger.getName();
|
||||
} else if(attributeName.equals("priority")) {
|
||||
Level l = logger.getLevel();
|
||||
if(l == null) {
|
||||
return null;
|
||||
} else {
|
||||
return l.toString();
|
||||
}
|
||||
} else if(attributeName.startsWith("appender=")) {
|
||||
try {
|
||||
return new ObjectName("log4j:"+attributeName );
|
||||
} catch(MalformedObjectNameException e) {
|
||||
cat.error("Could not create ObjectName" + attributeName);
|
||||
} catch(RuntimeException e) {
|
||||
cat.error("Could not create ObjectName" + attributeName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If attributeName has not been recognized throw an AttributeNotFoundException
|
||||
throw(new AttributeNotFoundException("Cannot find " + attributeName +
|
||||
" attribute in " + dClassName));
|
||||
|
||||
}
|
||||
|
||||
|
||||
void addAppender(String appenderClass, String appenderName) {
|
||||
cat.debug("addAppender called with "+appenderClass+", "+appenderName);
|
||||
Appender appender = (Appender)
|
||||
OptionConverter.instantiateByClassName(appenderClass,
|
||||
org.apache.log4j.Appender.class,
|
||||
null);
|
||||
appender.setName(appenderName);
|
||||
logger.addAppender(appender);
|
||||
|
||||
//appenderMBeanRegistration();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public
|
||||
void setAttribute(Attribute attribute) throws AttributeNotFoundException,
|
||||
InvalidAttributeValueException,
|
||||
MBeanException,
|
||||
ReflectionException {
|
||||
|
||||
// Check attribute is not null to avoid NullPointerException later on
|
||||
if (attribute == null) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("Attribute cannot be null"),
|
||||
"Cannot invoke a setter of " + dClassName +
|
||||
" with null attribute");
|
||||
}
|
||||
String name = attribute.getName();
|
||||
Object value = attribute.getValue();
|
||||
|
||||
if (name == null) {
|
||||
throw new RuntimeOperationsException(
|
||||
new IllegalArgumentException("Attribute name cannot be null"),
|
||||
"Cannot invoke the setter of "+dClassName+
|
||||
" with null attribute name");
|
||||
}
|
||||
|
||||
|
||||
if(name.equals("priority")) {
|
||||
if (value instanceof String) {
|
||||
String s = (String) value;
|
||||
Level p = logger.getLevel();
|
||||
if(s.equalsIgnoreCase("NULL")) {
|
||||
p = null;
|
||||
} else {
|
||||
p = OptionConverter.toLevel(s, p);
|
||||
}
|
||||
logger.setLevel(p);
|
||||
}
|
||||
} else {
|
||||
throw(new AttributeNotFoundException("Attribute " + name +
|
||||
" not found in " +
|
||||
this.getClass().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
void appenderMBeanRegistration() {
|
||||
Enumeration enumeration = logger.getAllAppenders();
|
||||
while(enumeration.hasMoreElements()) {
|
||||
Appender appender = (Appender) enumeration.nextElement();
|
||||
registerAppenderMBean(appender);
|
||||
}
|
||||
}
|
||||
|
||||
void registerAppenderMBean(Appender appender) {
|
||||
String name = getAppenderName(appender);
|
||||
cat.debug("Adding AppenderMBean for appender named "+name);
|
||||
ObjectName objectName = null;
|
||||
try {
|
||||
AppenderDynamicMBean appenderMBean = new AppenderDynamicMBean(appender);
|
||||
objectName = new ObjectName("log4j", "appender", name);
|
||||
if (!server.isRegistered(objectName)) {
|
||||
registerMBean(appenderMBean, objectName);
|
||||
dAttributes.add(new MBeanAttributeInfo("appender=" + name, "javax.management.ObjectName",
|
||||
"The " + name + " appender.", true, true, false));
|
||||
}
|
||||
|
||||
} catch(JMException e) {
|
||||
cat.error("Could not add appenderMBean for ["+name+"].", e);
|
||||
} catch(java.beans.IntrospectionException e) {
|
||||
cat.error("Could not add appenderMBean for ["+name+"].", e);
|
||||
} catch(RuntimeException e) {
|
||||
cat.error("Could not add appenderMBean for ["+name+"].", e);
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
void postRegister(java.lang.Boolean registrationDone) {
|
||||
appenderMBeanRegistration();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user