[PEAK] Error handling (was Re: Unifying configuration)

Phillip J. Eby pje at telecommunity.com
Sat Dec 20 11:26:03 EST 2003


At 12:32 PM 12/20/03 +0200, alexander smishlajev wrote:
>Phillip J. Eby wrote, at 20.12.2003 0:27:
>>
>>>pure ZConfig is a one-in-a-whole thing.  if there is an error (either 
>>>syntax error, or environment error, like missing directory, preventing 
>>>an instantiation of at least one component) the application does not 
>>>start at all, even if 90% of it are ok.  if we need to change a setting 
>>>for one component, we have to restart the whole application.
>>I would note that this is actually a good thing for end-user 
>>configuration, because it should prevent somebody breaking something and 
>>not noticing.
>
>i would agree with that, but the leader of our support staff is asking us 
>to implement starting with config errors.
>
>to address the issue of breaking something and not noticing we should have 
>a 'configtest' feature, touching each of the configured components to 
>validate their configuration.

Once we have the 'zconfig:' URL schema, you could use them in a binding 
with 'suggestParent=False', which would allow you load and instantiate the 
objects (validating the configuration) but not actually attaching them to 
the component hierarchy (and thus not activating their uponAssembly 
bindings).  Alternatively, using lookupComponent() with suggestParent=False 
would do the same thing, but wouldn't hold on to the created 
objects.  (I.e. you could just call lookupComponent() and throw the result 
away.)



>besides, errors in ZConfig file raise ecxeptions before anything of the 
>application is activated, so we cannot use common logging procedures and 
>have to produce a raw traceback that cannot be read and understood by 
>support people.

Interesting.  Well, if I add the zconfig: URL scheme as described in my 
previous message, it should be possible to do something like:

class WrappedConfig(binding.Component):

     filename = binding.Require("Filename to parse")
     url = binding.Make(lambda self: "zconfig:the.schema:file:%s" % 
self.filename)
     component = binding.Obtain(naming.Indirect('url'))

     def onStart(self):
         try:
             self.component
         except ZConfig.something:
             # whatever

     onStart = binding.Make(onStart, uponAssembly=True)

You could then use this around each file to be loaded.

Or, maybe there should be an 'onError=' keyword for bindings to let you set 
a handler for exceptions raised by a Make or Obtain?

Maybe certain kinds of components (such as commands) need to use an 
"application error handling" service of some kind, so that startup errors 
like ZConfig errors can not only be trapped, logged, and reported, but 
application-specific messages can be obtained.

On a related I've also considered having bindings trap computation errors 
and wrap them in a "BindingError" that would pinpoint the binding being 
computed.  But, this has the problem of *masking* the actual error causing 
the problem!  It may be that improved traceback formatting would be 
helpful, as John Landahl has previously suggested off-list.  Being able to 
replace file and line info with "context" information would be helpful, and 
that might be something an error handling service could do.  For example, 
if it is displaying a traceback that includes framework code, it could 
replace the file and line info with information like "Computing attribute 
foo on <bar object at 3459357>".

Hm.  One interesting way to do that, would be to use the __traceback_info__ 
variable used to do such things in Zope.  Ideally, one would '%' the 
variable with the frame locals as you display the traceback.  Then, by 
simply adding key assignments to __traceback_info__ in various parts of the 
framework, we could make it much easier to debug non-framework code, while 
giving friendlier error messages.  Further, since this would be done by a 
pluggable service, one could even have an i18n-friendly traceback formatter 
that translates the message prior to inserting the frame locals.

(It's interesting how the recent addition of the [Component Factories] 
sections has now made service components more attractive to add and use.)

Anyway, I'm not sure how all the details of error handling services should 
work.  To some extent, there are some ideas living inside peak.web error 
management already, and if we add a general error handling service it 
ideally should be usable there as well, so that web errors can be logged, etc.

It will probably also be the case that there will be more than one kind of 
error service.  One will probably be for logging/reporting them and maybe 
trapping/handling/displaying.  There will also probably need to be 
something specific for traceback formatting, used as a collaborator to 
other components.  That is, there might be a number of standard traceback 
formatters, but you might plug one in to your logging system, and a 
different one for end-user display or web viewing.  (Note that traceback 
formatting in the peak.running.logs subsystem should be replaced with use 
of a pluggable traceback formatter.)

I guess I need to stop volunteering to create all these new components, 
since my schedule at work is very busy right now.  The logger: and zconfig: 
changes are probably going to have to wait a while, let alone these new and 
undesigned-as-yet error services.  The "performance monitors" and "plugin 
support" changes are the highest priority for PEAK right now, followed by 
certain DB type conversion and stored procedure stuff, due to a project at 
work that needs all of those items.  But I may have some free time this or 
next weekend when I'll be able to work on some of the other things.

In the meantime, if you need to create a top-level error handler, you can 
always subclass ZConfigInterpreter or one of the related classes to trap 
errors.  You can then use an .ini to replace the current handler for either 
the ZConfig command or the zconfig.schema: URL with your subclass or 
subclasses, as needed.  That's one of the really nice things about PEAK: 
everything that really matters is subclassable, replaceable, and configurable.




More information about the PEAK mailing list