[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: [PATCH] libsvn_repos logging API -- first draft

From: Branko ─îibej <brane_at_xbc.nu>
Date: 2005-07-15 06:42:55 CEST

Ben Collins-Sussman wrote:

> +/** Accessors for repository's logfiles and loglevel. These things
> + * are set at runtime by the server (in something like svnserve.conf
> + * or httpd.conf).
> + */
> +
> +/** Set the error-logging threshold of @repos to @loglevel. Use @a

"@a repos to @a loglevel" ...

>
> +/** Write @a message into the accesslog of @a repos. If not @c NULL,
> + * then also include the following information in the log entry:
> + *
> + * @a process_name : the name of the process using libsvn_repos.
> + * (if @c NULL, write "(unknown process)").
> + * @a sockaddr : the IP address of the incoming request.
> + * (if @c NULL, write "(unknown IP)").
> + * @a username : the authenticated username attached to the
> request.
> + * (if @c NULL, write "(unknown user)").
> + *
> + * Use @a pool for temporary memory allocation.
> + */
> +svn_error_t *
> +svn_repos_write_accesslog (svn_repos_t *repos,
> + const char *process_name,
> + apr_sockaddr_t *sockaddr,
> + const char *username,
> + const char *message,
> + apr_pool_t *pool);

Hm. I wonder, wouldn't it be easier if you had an
svn_repos_set_process_name, and ommitted the process_name parameter
everywhere? After all, it's not very likely that different processes
would use the same svn_repos_t, or that the process' "name" would change
often.

IP and username change more often, but since it's likely that you'd
write more than one message per request, setting them separately might
make sense.

> +/** Write @a message into the errorlog of @a repos, if and only if the
> + * current loglevel of @a repos is greater than or equal to @a
> + * loglevel (see @c svn_repos_set_loglevel). If not @c NULL, then
> + * also include the following information in the log entry:
> + *
> + * @a process_name : the name of the process using libsvn_repos.
> + * (if @c NULL, write "(unknown process)").
> + *
> + * Use @a pool for temporary memory allocation.
> + */
> +svn_error_t *
> +svn_repos_write_errorlog (svn_repos_t *repos,
> + const char *process_name,
> + svn_repos_loglevel_t loglevel,
> + const char *message,
> + apr_pool_t *pool);

If you do keep the process_name parameter, please put it after the
loglevel. It seems cleaner that way.

One thing about this API has me worried, and that's the assumption that
you have to make a function call in order to check the log level; that
is, either svn_repos_write_errorlog checks the log level internally, or
some macro wrapper has to call svn_repos_get_loglevel before calling
svn_repos_write_errorlog.

Now, I hear people shouting "premature optimisation! function call
overhead is negligible!" Normally I'd agree, but i've been bitten by
this in error logging (debug tracing) systems before. What people tend
to forget is that when you write, e.g.,

  svn_repos_write_errorlog(repo, svn_repos_loglevel_debug,
                           "svnserve [$PID]",
                           apr_snprintf("gizmo %s frobbed twinkie %d",
                                        current_gizmo, current_twinkie),
                           pool);

all the function parameters get evaluated every time, regardless of
global log level. When you have many debug-level messages in the code,
those snprintf's pile up and can really slow things down.

A few years back we were using a tracing library that tested the trace
level inside the log functions. We were amazed that the server spent 25%
(!) of its CPU time in the tracing library (obviously, we relied quite a
bit on debug tracing). So we added wrappers that looked like this (using
the above AP)::

  #define SVN_REPOS_WRITE_ERRORLOG(repo, level, process, message, pool) \
    while { \
      svn_repos_loglevel_t loglevel; \
      SVN_ERR (svn_repos_get_loglevel (&loglevel, (repos), (pool))); \
      if ((level) <= loglevel) \
        SVN_ERR (svn_repos_write_errorlog ((repo), (level), (process), \
                                           (message), (pool))); \
    } while (0)

And suddenly our server ran 20% faster when the more verbose traces were
disabled.

Except that our API was different in two details:

    * The current log level was a global variable, so we didn't require
      a function call to retreive it.
    * The "write_errorlog" function did not return an error code.

Really, what are you going to do if your get_loglevel or write_errorlog
error out? Crash the server? I don't think so. By all means error out if
you can't open the log file, that usually happens at process startup.

This brings us to the accessor functions. As I understand it,
svn_repos_(get|set)_loglevel and svn_repos_(get|set)_(access|error)log
somply manipulate fields within the svn_repos_t. I fail to see how these
functions can fail (unless the svn_repos_t is NULL), or when they'd ever
need a pool -- any allocations they _do_ need can come from the
svn_repos_t's pool.

-- 
-- Brane
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Fri Jul 15 06:44:40 2005

This is an archived mail posted to the Subversion Dev mailing list.