Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hey Monks!

I've got a threaded program that uses modules. The main thread forks any number of children and the children make use of the modules. I'm also using log4perl.

This is all working just fine. However, I need to be able to change the log level while this is running. I threw in a signal handler to catch SIGUSR1 and lower the level using $logger->level(<new level>).

This works just fine for the main thread and the children, but the modules don't pick it up. This just doesn't make sense to me. They are using the same logger/appender as their respective threads...

Any ideas?

Thanks!!

Replies are listed 'Best First'.
Re: log level in modules
by tilly (Archbishop) on Aug 21, 2009 at 15:30 UTC
    Without knowing the guts of log4perl I'm going to guess that your configuration file specifies log levels for specific subclasses, and that more precise specification is overriding your attempt to set the logging level globally.

    If that is not it, then without knowing how your application is designed I'm going to guess that upon catching the signal you're creating a new $logger, which doesn't automatically get assigned to the $logger variables you've assigned in other modules. So after catching the signal your other modules are not using the same $logger any more.

    Either way the documentation for the module suggests that you should:

    Log::Log4perl::init_and_watch(’/etc/log4perl.conf’,10);
    If you do this then at run-time you can dynamically adjust the logging level of any and all pieces of your application at run-time. But with up to 10 second wait. If the wait is not critical to you, then I'd suggest taking that approach instead of using signals.

      Thanks, hadn't noticed this. The only problem is the performance hit (down to 45% could be very noticeable). There is a variance to have it reload upon a signal (only drops to 85%), but that would be a two step process. I'd like to understand why my way isn't working...

Re: log level in modules
by ikegami (Patriarch) on Aug 21, 2009 at 15:39 UTC

    The main thread forks any number of children

    When you say "forks", are you actually referring to the creation of new threads?

    This works just fine for the main thread and the children, but the modules don't pick it up.

    If the module is being used in a child thread, you say it both works and doesn't work. If the module is being used in the main thread, you say it both works and doesn't work. Since there's nowhere else in the process the module could be used, your problem description makes no sense.

      OK, some clarification:

      If we ignore the changing of log levels, everything works as expected.

      And here is the program flow:

      program start -> initialize logger <<Log::Log4perl::init("log.properti +es")>> -> get the logger <<my $logger = get_logger()>> -> use fork() +to create threads -> wait for threads to die
      child start -> change NDC <<Log::Log4perl::NDC->push($NDC)>> -> do the +ir thing, including using customer modules

      The modules use my $logger = get_logger() to get the logger. Messages from the modules use the correct NDC as configured for each thread.

      Let's say my module is as simple as:

      use Log::Log4perl (get_logger); my $logger = get_logger(); sub sayHello { $logger->info("Hello world!"); }

      Doesn't that mean that every time a thread executes that sayHello sub, the module gets the logger then logs a message?

      If so, why doesn't it get the new logging level? If I start with level WARN specified in my config file, I don't expect to see the message in my logs. That part works just fine. If I then use the signal to lower the level to INFO, I would expect to see the message start appearing in the log. It doesn't.

        use fork() to create threads

        fork doesn't create threads*, it creates new processes which are copies of the parent. You're only sending the signal the parent process, so nothing changes the copies of the logger objects found in the child processes.

        Even if you did create threads, Perl gives each thread a copy of every Perl variable except for variables that had been shared explicitly. You didn't create a shared variable that holds a logger object, and I doubt that the logger does this for you.

        * — Except in Windows. fork is emulated using threads in Windows.