1

I am trying to write a logger role (with Log::Dispatchouli, but that shouldn't matter) that tells me from which package, sub, line etc. I have been issuing log messages. Naturally, I tried with caller, but stack is full of Moose classes and the number of frames changes in different situations. Is there a way to get similar info using MOP or Moose? Or perhaps there is a module to filter caller stack? Thanks a lot!

package logger

sub log {...}

#some_package
log "bla"

#intended output
some_package l.12 bla
Kara
  • 6,115
  • 16
  • 50
  • 57
mokko
  • 186
  • 9

1 Answers1

6

You can use Carp's longmess function to produce a stack trace. It's poorly documented, but its been there for a long time and pretty safe to use. cluck and confess are just warn longmess and die longmess respectively.

The advantage of using longmess() is Carp has several global variables to control what it considers to be "internal". This effectively stops them from appearing in stack traces. The two you care about are @CARP_NOT and %Carp::Internal. Which you should use depends on how you're logging.

@CARP_NOT affects only stack traces originating from the package that set @CARP_NOT. So you could write your logger something like this:

package MyLogger;

use Carp;
our @CARP_NOT = qw(MyLogger Moose More::Moose::Stuff);

sub trace {
    # For example...
    warn Carp::longmess("Trace message");
}

MyLogger::trace() should report a trace message but ignore itself, Moose and whatever else you put into @CARP_NOT.

%Carp::Internal is sort of a global version of this. If you can't centralize where the Carp functions are called into a logging package, you can add packages to %Carp::Internal. Unfortunately this is global and has all the problems of setting a global variable. If you're going to mess with it, be sure to add packages to it like $Carp::Internal{"Some::Module"}++. Do not overwrite it like %Carp::Internal = ("Some::Module" => 1).

cjm
  • 61,471
  • 9
  • 126
  • 175
Schwern
  • 153,029
  • 25
  • 195
  • 336