I'm writing an asynchronous event interceptor and running into an
issue with the asynchronous file logging appender in Logbox. The
problem, fundamentally, is that the AsyncLogFileAppender uses cfthread
to spawn the log write action but you can't run cfthread from within
cfthread, so if you main application logic uses cfthread, any logging
will end up throwing an error trying to nest cfthread tags.
I'm unsure what the best way to solve the issue is. I was thinking
about dynamically rewriting the log appenders to use the general
FileAppender if the Root Logger uses an asynchronous log appender and
then dynamically swapping it back at the end of my interceptor but
that seems like quite the hack.
Perhaps a better method would be to wrap a try/catch around the call
to cfthread in AsyncFileAppender.cfc and if it throws an error about
nested cfthread calls, revert it to a normal, non-threaded, call to
append(attributes.entry). This would keep the performance gains for
existing applications while also making the built-in logging work for
applications using cfthread themselves.
That's nice Mark, I really didn't think there was any way to tell if
you were instead a cfthread spawned execution path or not. It is up to
Luis, of course, to decide whether or not he wants to implement that
sort of check with the Asynchronous Log File Appender or not, but I
think it is an excellent idea and I'll implement it locally while we
wait to hear what Luis thinks.
Hmm...alas, it looks like Railo doesn't return the same value for the
thread group that Adobe does. In fact, it returns a blank string. I'll
submit that as a feature request to Railo so there is compatibility
but I guess that's what we get for relying upon an undocumented
feature.
I guess I'll either go back to using try/catch or else come up with
some other way to distinguish between normal page threads and cfthread
spawned threads.
An interesting check could be to see what Railo uses for a Thread name for their General purpose web request threads, as if you are in there, you know you aren’t in a cfthread.
The main thread name seems to be of the form
HTTP-*portnumber*-*increment* so when I looked at it earlier today it
was HTTP-8080-2 on the built-in Tomcat webserver.
I'm going to run some more tests tomorrow. It occurred to me that I
should go look at Railo's internal code. I know that the thread being
spawned by a thread is not a Java limitation, so it must be a check
that Railo/ACF is doing. Therefore we should be able to do the same
check ourselves.
Here are the results of my investigation so far on Railo 3.1.2, CF 8
and CF 9. I don't have OpenBD installed on this box, so I'll ask
someone else to investigate that.
Railo: same name for both the page thread and the spawned thread (both
called "main")
CF 8: "jrpp" for page thread and "cfthread" for spawned thread
CF 9 (built in webserver): "web" for page thread and "cfthread" for
spawned thread.
I did find a way with Railo, however, to tell if you are in a cfthread
or not. Railo has a function called hasFamily() of off
GetPageContext() So in Railo, the following code:
results in "False" on the main page thread and "True" inside the
spawned thread. I could not find a comparable function in ACF after
poking around their implementation of GetPageContext()
So thus far it looks like the best way to check is to check the Thread
Group name for ACF and to check GetPageContext.hasFamily() for Railo.
Not terribly clean or consistent, alas, but the best I can do so far.
This has been added yesterday to the core and also to logbox. Nice little tool to find if you are in a thread in any CFMLEngine.
Luis F. Majano
President
Ortus Solutions, Corp