What prevents you from writing a more compact representation of the
LogEvent (including all other LogEvent fields) to the byte array in the
{{toByteArray(LogEvent)}} method of an ExternalizableLayout?


On Sat, Jul 12, 2014 at 12:45 AM, Scott Harrington <scott...@sns-usa.com>
wrote:

> I looked at replacing SerializedLayout and/or the toSerializable method
> but the real savings comes not from the Message itself but from all the
> other fields of the LogEvent, such as the Level, ContextMap, ContextStack,
> and the class descriptor (including superclasses) of the LogEvent itself.
>
> For big messages, an ExternalizableLayout would be a fine solution,
> because writeUTF would give you roughly 50% compression over Java's default
> 2-byte per char String serialization.
>
> However for typical log messages the message itself is being dwarfed on
> the wire by class descriptor overhead.
>
>
>
> On Sat, 12 Jul 2014, Remko Popma wrote:
>
>  That is a nice reduction in size!
>>
>> I also think the ExternalizedLayout idea is a very attractive option. That
>> way there is no pressure to include this in any particular release, we can
>> release it when we are confident that is ready. I also like the fact that
>> it does not replace the current serialization and it can be switched on
>> and
>> off in configuration so if there is a bug, users can fall back to the
>> existing plain serialization.
>>
>>
>>
>> On Fri, Jul 11, 2014 at 10:00 PM, Matt Sicker <boa...@gmail.com> wrote:
>>
>>  I would second the ExternalizedLayout. Layouts are the way to go for
>>> compatibility and are simpler. Particularly useful for alternative
>>> serialization protocols, too.
>>>
>>>
>>> On 11 July 2014 06:41, Gary Gregory <garydgreg...@gmail.com> wrote:
>>>
>>>  I understand Ralph ' s concern but now is the time for this kind of
>>>> change.  Otherwise we will need even more clever solutions to get this
>>>>
>>> kind
>>>
>>>> of size improvement. I'd love to see some performance numbers. The size
>>>> improvement is not negligible, which is great!
>>>>
>>>> Gary
>>>>
>>>>
>>>>
>>>> <div>-------- Original message --------</div><div>From: Ralph Goers <
>>>> ralph.go...@dslextreme.com> </div><div>Date:07/11/2014  01:46
>>>>  (GMT-05:00) </div><div>To: Log4J Users List <
>>>> log4j-user@logging.apache.org> </div><div>Subject: Re: Make LogEvent
>>>> implementations Externalizable </div><div>
>>>> </div>I’d be afraid of breaking compatibility even now.  However, I
>>>> think
>>>> what you really want to do is to create an ExternalizedLayout and then
>>>>
>>> just
>>>
>>>> use that instead of the default SerializedLayout.  If you want to supply
>>>> that Layout as a patch to a Jira issue it could be added at any time.
>>>>
>>>> Ralph
>>>>
>>>> On Jul 10, 2014, at 9:23 PM, Scott Harrington <scott...@sns-usa.com>
>>>> wrote:
>>>>
>>>>  Ralph & co:
>>>>>
>>>>> I hear you're gearing up for the release.
>>>>>
>>>>> Last weekend I scratched an itch of mine relating to SocketAppender ->
>>>>>
>>>> SocketServer bandwidth, and was able to reduce a 500-character message
>>>>
>>> from
>>>
>>>> around 1700 bytes to 700 bytes on the wire (it's easy to improve on
>>>>
>>> Java's
>>>
>>>> default serialization).
>>>>
>>>>>
>>>>> I was going to submit an enhancement request with patch to JIRA but
>>>>>
>>>> instead I went on vacation for two weeks.
>>>>
>>>>>
>>>>> I made RingBufferLogEvent implement Externalizable, i.e. hand-coded
>>>>>
>>>> writeExternal / readExternal methods. I did NOT have time to make an
>>>> equivalent change to Log4jLogEvent, or to write up any performance tests
>>>>
>>> or
>>>
>>>> regression tests.
>>>>
>>>>>
>>>>> Should I submit what I have for discussion and hopeful inclusion in
>>>>>
>>>> 2.0?
>>>
>>>>
>>>>> Or will it have to wait for 2.1?
>>>>>
>>>>> If we wait, then due to the necessary serialVersionUID change, v2.0
>>>>>
>>>> SocketAppender would not be able to talk to v2.1 SocketServer or vice
>>>>
>>> versa
>>>
>>>> (unless ugly duplicate versions are maintained).
>>>>
>>>>>
>>>>> Below is what the added code looks like. I only tested in
>>>>>
>>>> RingBufferLogEvent but should be similarly usable in Log4jLogEvent, and
>>>> perhaps we should discuss a RingBufferLogEvent.readResolve that makes
>>>>
>>> them
>>>
>>>> all become Log4jLogEvents on the SocketServer (receiving) end.
>>>>
>>>>>
>>>>> ...
>>>>>
>>>>>    public void writeExternal(ObjectOutput out) throws IOException {
>>>>>        getThrownProxy();
>>>>>        out.writeByte(1); // wireFormat
>>>>>        int presenceMap = (loggerName == null ? 0 : 0x1) |
>>>>>            (marker == null ? 0 : 0x2) |
>>>>>            (fqcn == null ? 0 : 0x4) |
>>>>>            (level == null ? 0 : 0x8) |
>>>>>            (message == null ? 0 : (0x10 | (isSerializeAsString(message)
>>>>>
>>>> ? 0 : 0x20))) |
>>>>
>>>>>            (thrownProxy == null ? 0 : 0x40) |
>>>>>            (contextMap == null ? 0 : 0x80) |
>>>>>            (contextStack == null ? 0 : 0x100 | (contextStack.getDepth()
>>>>>
>>>> == 0 ? 0 : 0x200)) |
>>>>
>>>>>            (threadName == null ? 0 : 0x400) |
>>>>>            (location == null ? 0 : 0x800);
>>>>>        out.writeShort(presenceMap);
>>>>>        if (loggerName != null) {
>>>>>            out.writeUTF(loggerName);
>>>>>        }
>>>>>        if (marker != null) {
>>>>>            out.writeObject(marker);
>>>>>        }
>>>>>        if (fqcn != null) {
>>>>>            out.writeUTF(fqcn);
>>>>>        }
>>>>>        if (level != null) {
>>>>>            out.writeUTF(level.name());
>>>>>        }
>>>>>        if (message != null) {
>>>>>            if (isSerializeAsString(message)) {
>>>>>                out.writeUTF(message.getFormattedMessage());
>>>>>            }
>>>>>            else {
>>>>>                out.writeObject(message);
>>>>>            }
>>>>>        }
>>>>>        if (thrownProxy != null) {
>>>>>            out.writeObject(thrownProxy);
>>>>>        }
>>>>>        if (contextMap != null) {
>>>>>            writeString2StringMap(out, contextMap);
>>>>>        }
>>>>>        if (contextStack != null && contextStack.getDepth() != 0) {
>>>>>            out.writeObject(contextStack);
>>>>>        }
>>>>>        if (threadName != null) {
>>>>>            out.writeUTF(threadName);
>>>>>        }
>>>>>        if (location != null) {
>>>>>            out.writeUTF(location.getClassName());
>>>>>            out.writeUTF(location.getMethodName());
>>>>>            if ((presenceMap & 0x1000) != 0) {
>>>>>                out.writeUTF(location.getFileName());
>>>>>            }
>>>>>            out.writeInt(location.getLineNumber());
>>>>>        }
>>>>>        out.writeLong(currentTimeMillis);
>>>>>        out.writeBoolean(endOfBatch);
>>>>>        out.writeBoolean(includeLocation);
>>>>>    }
>>>>>
>>>>>    public void readExternal(ObjectInput in) throws IOException,
>>>>>
>>>> ClassNotFoundException {
>>>>
>>>>>        int wireFormat = in.readByte();
>>>>>        if (wireFormat == 1) {
>>>>>            int presenceMap = in.readShort();
>>>>>            loggerName = (presenceMap & 0x1) == 0 ? null :
>>>>>                in.readUTF();
>>>>>            marker = (presenceMap & 0x2) == 0 ? null :
>>>>>                (Marker) in.readObject();
>>>>>            fqcn = (presenceMap & 0x4) == 0 ? null :
>>>>>                in.readUTF();
>>>>>            level = (presenceMap & 0x8) == 0 ? null :
>>>>>                Level.valueOf(in.readUTF());
>>>>>            message = (presenceMap & 0x10) == 0 ? null :
>>>>>                (presenceMap & 0x20) == 0 ? new
>>>>>
>>>> SimpleMessage(in.readUTF()) : (Message) in.readObject();
>>>>
>>>>>            thrownProxy = (presenceMap & 0x40) == 0 ? null :
>>>>>                (ThrowableProxy) in.readObject();
>>>>>            contextMap = (presenceMap & 0x80) == 0 ? null :
>>>>>                readString2StringMap(in);
>>>>>            contextStack = (presenceMap & 0x100) == 0 ? null :
>>>>>                (presenceMap & 0x200) == 0 ? ThreadContext.EMPTY_STACK :
>>>>>
>>>> (ContextStack) in.readObject();
>>>>
>>>>>            threadName = (presenceMap & 0x400) == 0 ? null :
>>>>>                in.readUTF();
>>>>>            location = (presenceMap & 0x800) == 0 ? null :
>>>>>                new StackTraceElement(in.readUTF(), in.readUTF(),
>>>>>
>>>> (presenceMap & 0x1000) == 0 ? null : in.readUTF(), in.readInt());
>>>>
>>>>>            currentTimeMillis = in.readLong();
>>>>>            endOfBatch = in.readBoolean();
>>>>>            includeLocation = in.readBoolean();
>>>>>        }
>>>>>        else {
>>>>>            throw new StreamCorruptedException("Unsupported LogEvent
>>>>>
>>>> wire
>>>
>>>> format " + wireFormat);
>>>>
>>>>>        }
>>>>>    }
>>>>>
>>>>>    private static boolean isSerializeAsString(Message message)
>>>>>    {
>>>>>        return message instanceof SimpleMessage || message instanceof
>>>>>
>>>> ObjectMessage;
>>>>
>>>>>    }
>>>>>
>>>>>    private void writeString2StringMap(ObjectOutput out, Map<String,
>>>>>
>>>> String> map) throws IOException
>>>>
>>>>>    {
>>>>>        out.writeInt(map.size());
>>>>>        for (Map.Entry<String, String> entry : map.entrySet()) {
>>>>>            out.writeUTF(entry.getKey());
>>>>>            out.writeUTF(entry.getValue());
>>>>>        }
>>>>>    }
>>>>>
>>>>>    private static Map<String, String> readString2StringMap(ObjectInput
>>>>>
>>>> in) throws ClassNotFoundException, IOException
>>>>
>>>>>    {
>>>>>        int size = in.readInt();
>>>>>        if (size == 0) {
>>>>>            return Collections.emptyMap();
>>>>>        }
>>>>>        Map<String, String> map = new HashMap<String, String>(size);
>>>>>        while (size-- > 0) {
>>>>>            map.put(in.readUTF(), in.readUTF());
>>>>>        }
>>>>>        return map;
>>>>>    }
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org
>>>>> For additional commands, e-mail: log4j-user-h...@logging.apache.org
>>>>>
>>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org
>>>> For additional commands, e-mail: log4j-user-h...@logging.apache.org
>>>>
>>>>
>>>>
>>>
>>> --
>>> Matt Sicker <boa...@gmail.com>
>>>
>>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: log4j-user-unsubscr...@logging.apache.org
> For additional commands, e-mail: log4j-user-h...@logging.apache.org
>

Reply via email to