Sure. Since the class name lookups will only be used for debugging, they
can be as generic as necessary, as long it doesn't add any requirements
to users. Match-on-load and match-on-demand are both fine.
On 23-03-2012 13:19, Matthew Toseland wrote:
> On Friday 23 Mar 2012 16:00:15 Marco Schulze wrote:
>> Yes, and yes.
>>
>> On 23-03-2012 12:43, Matthew Toseland wrote:
>>> On Friday 23 Mar 2012 15:29:44 you wrote:
>>>> Right now, the map is only used to list class thresholds which are
>>>> different from the global threshold, which means it is empty 99% of the
>>>> time. This is the simplest solution, but it also means that the
>>>> possibility of lock contention is way higher. However, unless this
>>>> proves to be very bad in a real run, I'll stick with it.
>>> Sounds like you need to use a volatile.
>>>
>>> Also your design implies that the log level details will be changed to not
>>> support wildcards/prefixes?
> Is there any way to avoid this? Prefixes are really handy in some debugging
> situations. Possibly we could hook into the classloader and apply the
> wildcards on loading?
>
>>>> On 23-03-2012 10:39, Matthew Toseland wrote:
>>>>> On Friday 23 Mar 2012 00:18:02 Marco Schulze wrote:
>>>>>> I already have all but log rotation and async ready, and haven't yet
>>>>>> found a single benchmark supporting the use of a branch as the
>>>>>> performance holy grail. For example (outputting to /dev/null):
>>>>>>
>>>>>> public static void main (String[] args) {
>>>>>> for (int i = 0; i< 1000000; i++) {
>>>>>> Log.fatal (Log.class, Log.class, "akd\n\n", i, '\n',
>>>>>> out, ' ');
>>>>>> Log.trace (Log.class, Log.class, "akd\n\n", i, '\n',
>>>>>> out, ' ');
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> Every call means, minimally, varargs boxing, another call (since fatal()
>>>>>> and trace() are simple convenience methods) and an isLoggable() check
>>>>>> composed by a ConcurrentHashMap lookup against the class name and
>>>>>> (possibly) a synchronized read on the global threshold. trace() is
>>>>>> filtered but fatal() is not.
>>>>> Don't do a synchronized read on the global threshold. Don't do
>>>>> synchronized anything. Just recompute all the classes when the thresholds
>>>>> change.
>>>>>
>>>>> However, you still haven't told me how you're going to ensure all classes
>>>>> are paged in when you do set all the thresholds in the map?
>>>>>> This snipped ran in an average 6.482 seconds. If the call to trace() is
>>>>>> commented out (thus removing the filtering overhead), the average falls
>>>>>> to 6.366 seconds. Disabling JIT, the figures became 1:37.952 and
>>>>>> 1:35.880, respectively. Over a million calls, checking costs only a few
>>>>>> milliseconds.
>>>>>>
>>>>>> To be sure, this is a fairly simple example: it all runs on a single
>>>>>> thread, the hash table is empty and the pressure on the GC is low.
>>>>>> Still, differences are very small. Plus, there's no overhead due to a
>>>>>> dedicated logging thread.
>>>>>>
>>>>>> On 22-03-2012 18:59, Zlatin Balevsky wrote:
>>>>>>> Double-digit millisecond pauses are not nothing. They may be
>>>>>>> acceptable right now but unless you can offer a drastically cleaner
>>>>>>> syntax Fred should stick with predicates as they are handled much
>>>>>>> better by the hotspot jit.
>>>>>>>
>>>>>>> On Mar 22, 2012 5:36 PM, "Ximin Luo"<infinity0 at gmx.com
>>>>>>> <mailto:infinity0 at gmx.com>> wrote:
>>>>>>>
>>>>>>> Lazy evaluation is trivial.
>>>>>>>
>>>>>>> Log.info("{1} did {2}",
>>>>>>> new Object(){ public String toString() { return ITEM_1; } },
>>>>>>> new Object(){ public String toString() { return ITEM_2; } }
>>>>>>> );
>>>>>>>
>>>>>>> Garbage collection with short-lived objects costs next to
>>>>>>> nothing.
>>>>>>>
>>>>>>> On 22/03/12 21:15, Zlatin Balevsky wrote:
>>>>>>> > Constructing the logging strings is half of the problem.
>>>>>>> The
>>>>>>> amount of garbage
>>>>>>> > they will generate will result in significantly more time in
>>>>>>> garbage collection
>>>>>>> > pauses.
>>>>>>> >
>>>>>>> > Unless you figure out a way to mimic lazy evaluation you
>>>>>>> have to
>>>>>>> live with the
>>>>>>> > isLoggable predicates. varargs are not an option either
>>>>>>> because
>>>>>>> they also
>>>>>>> > create garbage.
>>>>>>> >
>>>>>>> > On Mar 22, 2012 8:11 AM, "Marco Schulze"
>>>>>>> <marco.c.schulze at gmail.com<mailto:marco.c.schulze at
>>>>>>> gmail.com>
>>>>>>> > <mailto:marco.c.schulze at gmail.com
>>>>>>> <mailto:marco.c.schulze at gmail.com>>> wrote:
>>>>>>> >
>>>>>>> >
>>>>>>> >
>>>>>>> > On 22-03-2012 08:50, Matthew Toseland wrote:
>>>>>>> >
>>>>>>> > On Wednesday 21 Mar 2012 21:18:37 Marco Schulze
>>>>>>> wrote:
>>>>>>> >
>>>>>>> > There are basically two big concerns regarding
>>>>>>> logging in fred:
>>>>>>> >
>>>>>>> > - Readability and code clutter, which was my
>>>>>>> original questioning;
>>>>>>> > - Raw throughput, as raised by toad.
>>>>>>> >
>>>>>>> > Point 1 could mostly be solved by removing any
>>>>>>> traces of logMINOR and
>>>>>>> > logDEBUG on all but the few places where
>>>>>>> generating
>>>>>>> messages to be
>>>>>>> > logged brings noticeable slowdown. That'd be
>>>>>>> enough,
>>>>>>> but, personally,
>>>>>>> > the mess that the logging backend is does
>>>>>>> warrant a
>>>>>>> replacement.
>>>>>>> > According to toad, the current system needs
>>>>>>> log{MINOR,DEBUG} to
>>>>>>> > function
>>>>>>> > in a timely manner. Based on this, I think we
>>>>>>> all
>>>>>>> agree a
>>>>>>> > replacement is
>>>>>>> > desirable.
>>>>>>> >
>>>>>>> > Logging has a few additional requirements:
>>>>>>> >
>>>>>>> > - Log rotation (possibly live);
>>>>>>> > - Reentrant;
>>>>>>> > - Per-class filtering;
>>>>>>> > - Specific information in log (class-name, for
>>>>>>> example).
>>>>>>> >
>>>>>>> > Now, _any_ library which fits would make me
>>>>>>> happy,
>>>>>>> as long as they
>>>>>>> > agree
>>>>>>> > to two points:
>>>>>>> >
>>>>>>> > - Either lightweight or with optional features.
>>>>>>> Else, it would only
>>>>>>> > transfer bloat to freenet-ext.jar. For example:
>>>>>>> log2socket, config
>>>>>>> > management and multiple logging instances;
>>>>>>> > - Implementable in a few LoC. Specially, it
>>>>>>> shouldn't need specialized
>>>>>>> > Formatter and Writer.
>>>>>>> >
>>>>>>> > Plus, it should be fast.
>>>>>>> >
>>>>>>> > From the quick research I made (yep, too
>>>>>>> many lists):
>>>>>>> >
>>>>>>> > - SLF4J already fails on point one: it is
>>>>>>> simply a
>>>>>>> wrapper;
>>>>>>> > - The Java logging API fails on point two:
>>>>>>> specialized classes would
>>>>>>> > have to be written to deal with log rotation,
>>>>>>> per-class filtering and
>>>>>>> > formatting, plus a wrapper for
>>>>>>> Logger.{info,warning,...}() methods.
>>>>>>> > Exactly the same as a custom logger, with one
>>>>>>> more
>>>>>>> dependency and using
>>>>>>> > more LoC;
>>>>>>> >
>>>>>>> > No dependancies, it's part of the JDK, isn't it?
>>>>>>> >
>>>>>>> > More classes need to be loaded at startup. It's just me
>>>>>>> thinking too much.
>>>>>>> >
>>>>>>> >
>>>>>>> > However, if it's not a clearer/simpler API, it
>>>>>>> probably
>>>>>>> doesn't make
>>>>>>> > much sense.
>>>>>>> >
>>>>>>> > - Log4J seems to fail on point one - it only
>>>>>>> lacks a
>>>>>>> button that brings
>>>>>>> > back the dead. It seems interesting, and I
>>>>>>> haven't
>>>>>>> dropped this yet.
>>>>>>> >
>>>>>>> > In either case (custom or external), log* would
>>>>>>> be
>>>>>>> banished. Forever.
>>>>>>> >
>>>>>>> > I don't follow. You object to using a separate logs
>>>>>>> folder?
>>>>>>> >
>>>>>>> > log* == log{MINOR,DEBUG}, not the logs folder.
>>