{"id":27197714,"url":"https://github.com/preaction/log-any","last_synced_at":"2026-04-06T06:32:41.315Z","repository":{"id":25274737,"uuid":"28700338","full_name":"preaction/Log-Any","owner":"preaction","description":"Simple, fast Perl logging API compatible with any logging system","archived":false,"fork":false,"pushed_at":"2023-11-19T00:07:21.000Z","size":595,"stargazers_count":13,"open_issues_count":24,"forks_count":19,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-06-18T11:17:35.414Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/preaction.png","metadata":{"files":{"readme":"README.mkdn","changelog":"Changes","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-01-02T01:29:38.000Z","updated_at":"2024-06-18T11:17:41.276Z","dependencies_parsed_at":"2024-06-18T11:27:42.138Z","dependency_job_id":null,"html_url":"https://github.com/preaction/Log-Any","commit_stats":{"total_commits":450,"total_committers":26,"mean_commits":"17.307692307692307","dds":0.6266666666666667,"last_synced_commit":"31e42a54888fe4fc12db1e760c8ae18ac48b8be4"},"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/preaction%2FLog-Any","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/preaction%2FLog-Any/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/preaction%2FLog-Any/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/preaction%2FLog-Any/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/preaction","download_url":"https://codeload.github.com/preaction/Log-Any/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248106808,"owners_count":21048799,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-04-09T20:29:25.610Z","updated_at":"2026-04-06T06:32:41.308Z","avatar_url":"https://github.com/preaction.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NAME\n\nLog::Any - Bringing loggers and listeners together\n\n# VERSION\n\nversion 1.719\n\n# SYNOPSIS\n\nIn a CPAN or other module:\n\n    package Foo;\n    use Log::Any qw($log);\n\n    # log a string\n    $log-\u003eerror(\"an error occurred\");\n\n    # log a string and some data\n    $log-\u003einfo(\"program started\",\n        {progname =\u003e $0, pid =\u003e $$, perl_version =\u003e $]});\n\n    # log a string and data using a format string\n    $log-\u003edebugf(\"arguments are: %s\", \\@_);\n\n    # log an error and throw an exception\n    die $log-\u003efatal(\"a fatal error occurred\");\n\nIn a Moo/Moose-based module:\n\n    package Foo;\n    use Log::Any ();\n    use Moo;\n\n    has log =\u003e (\n        is =\u003e 'ro',\n        default =\u003e sub { Log::Any-\u003eget_logger },\n    );\n\nIn your application:\n\n    use Foo;\n    use Log::Any::Adapter;\n\n    # Send all logs to Log::Log4perl\n    Log::Any::Adapter-\u003eset('Log4perl');\n\n    # Send all logs to Log::Dispatch\n    my $log = Log::Dispatch-\u003enew(outputs =\u003e [[ ... ]]);\n    Log::Any::Adapter-\u003eset( 'Dispatch', dispatcher =\u003e $log );\n\n    # See Log::Any::Adapter documentation for more options\n\n# DESCRIPTION\n\n`Log::Any` provides a standard log production API for modules.\n[Log::Any::Adapter](https://metacpan.org/pod/Log%3A%3AAny%3A%3AAdapter) allows applications to choose the mechanism for log\nconsumption, whether screen, file or another logging mechanism like\n[Log::Dispatch](https://metacpan.org/pod/Log%3A%3ADispatch) or [Log::Log4perl](https://metacpan.org/pod/Log%3A%3ALog4perl).\n\nMany modules have something interesting to say. Unfortunately there is no\nstandard way for them to say it - some output to STDERR, others to `warn`,\nothers to custom file logs. And there is no standard way to get a module to\nstart talking - sometimes you must call a uniquely named method, other times\nset a package variable.\n\nThis being Perl, there are many logging mechanisms available on CPAN.  Each has\ntheir pros and cons. Unfortunately, the existence of so many mechanisms makes\nit difficult for a CPAN author to commit his/her users to one of them. This may\nbe why many CPAN modules invent their own logging or choose not to log at all.\n\nTo untangle this situation, we must separate the two parts of a logging API.\nThe first, _log production_, includes methods to output logs (like\n`$log-\u003edebug`) and methods to inspect whether a log level is activated\n(like `$log-\u003eis_debug`). This is generally all that CPAN modules care\nabout. The second, _log consumption_, includes a way to configure where\nlogging goes (a file, the screen, etc.) and the code to send it there. This\nchoice generally belongs to the application.\n\nA CPAN module uses `Log::Any` to get a log producer object.  An application,\nin turn, may choose one or more logging mechanisms via [Log::Any::Adapter](https://metacpan.org/pod/Log%3A%3AAny%3A%3AAdapter), or\nnone at all.\n\n`Log::Any` has a very tiny footprint and no dependencies beyond Perl 5.8.1,\nwhich makes it appropriate for even small CPAN modules to use. It defaults to\n'null' logging activity, so a module can safely log without worrying about\nwhether the application has chosen (or will ever choose) a logging mechanism.\n\nSee [http://www.openswartz.com/2007/09/06/standard-logging-api/](http://www.openswartz.com/2007/09/06/standard-logging-api/) for the\noriginal post proposing this module.\n\n# LOG LEVELS\n\n`Log::Any` supports the following log levels and aliases, which is meant to be\ninclusive of the major logging packages:\n\n     trace\n     debug\n     info (inform)\n     notice\n     warning (warn)\n     error (err)\n     critical (crit, fatal)\n     alert\n     emergency\n\nLevels are translated as appropriate to the underlying logging mechanism. For\nexample, log4perl only has six levels, so we translate 'notice' to 'info' and\nthe top three levels to 'fatal'.  See the documentation of an adapter class\nfor specifics.\n\n# CATEGORIES\n\nEvery logger has a category, generally the name of the class that asked for the\nlogger. Some logging mechanisms, like log4perl, can direct logs to different\nplaces depending on category.\n\n# PRODUCING LOGS (FOR MODULES)\n\n## Getting a logger\n\nThe most convenient way to get a logger in your module is:\n\n    use Log::Any qw($log);\n\nThis creates a package variable _$log_ and assigns it to the logger for the\ncurrent package. It is equivalent to\n\n    our $log = Log::Any-\u003eget_logger;\n\nIn general, to get a logger for a specified category:\n\n    my $log = Log::Any-\u003eget_logger(category =\u003e $category)\n\nIf no category is specified, the calling package is used.\n\nA logger object is an instance of [Log::Any::Proxy](https://metacpan.org/pod/Log%3A%3AAny%3A%3AProxy), which passes\non messages to the [Log::Any::Adapter](https://metacpan.org/pod/Log%3A%3AAny%3A%3AAdapter) handling its category.\n\nIf the `proxy_class` argument is passed, an alternative to\n[Log::Any::Proxy](https://metacpan.org/pod/Log%3A%3AAny%3A%3AProxy) (such as a subclass) will be instantiated and returned\ninstead.  The argument is automatically prepended with \"Log::Any::Proxy::\".\nIf instead you want to pass the full name of a proxy class, prefix it with\na \"+\". E.g.\n\n    # Log::Any::Proxy::Foo\n    my $log = Log::Any-\u003eget_logger(proxy_class =\u003e 'Foo');\n\n    # MyLog::Proxy\n    my $log = Log::Any-\u003eget_logger(proxy_class =\u003e '+MyLog::Proxy');\n\n## Logging\n\nTo log a message, pass a single string to any of the log levels or aliases. e.g.\n\n    $log-\u003eerror(\"this is an error\");\n    $log-\u003ewarn(\"this is a warning\");\n    $log-\u003ewarning(\"this is also a warning\");\n\nThe log string will be returned so that it can be used further (e.g. for a `die` or\n`warn` call).\n\nYou should **not** include a newline in your message; that is the responsibility\nof the logging mechanism, which may or may not want the newline.\n\nIf you want to log additional structured data alongside with your string, you\ncan add a single hashref after your log string. e.g.\n\n    $log-\u003einfo(\"program started\",\n        {progname =\u003e $0, pid =\u003e $$, perl_version =\u003e $]});\n\nIf the configured [Log::Any::Adapter](https://metacpan.org/pod/Log%3A%3AAny%3A%3AAdapter) does not support logging structured data,\nthe hash will be converted to a string using [Data::Dumper](https://metacpan.org/pod/Data%3A%3ADumper).\n\nThere are also versions of each of the logging methods with an additional \"f\" suffix\n(`infof`, `errorf`, `debugf`, etc.) that format a list of arguments.  The\nspecific formatting mechanism and meaning of the arguments is controlled by the\n[Log::Any::Proxy](https://metacpan.org/pod/Log%3A%3AAny%3A%3AProxy) object.\n\n    $log-\u003eerrorf(\"an error occurred: %s\", $@);\n    $log-\u003edebugf(\"called with %d params: %s\", $param_count, \\@params);\n\nBy default it renders like [`sprintf`](https://metacpan.org/pod/perlfunc#sprintf-FORMAT-LIST),\nwith the following additional features:\n\n- Any complex references (like `\\@params` above) are automatically converted to\nsingle-line strings with [Data::Dumper](https://metacpan.org/pod/Data%3A%3ADumper).\n- Any undefined values are automatically converted to the string \"\u0026lt;undef\u003e\".\n\n## Log level detection\n\nTo detect whether a log level is on, use \"is\\_\" followed by any of the log\nlevels or aliases. e.g.\n\n    if ($log-\u003eis_info()) { ... }\n    $log-\u003edebug(\"arguments are: \" . Dumper(\\@_))\n        if $log-\u003eis_debug();\n\nThis is important for efficiency, as you can avoid the work of putting together\nthe logging message (in the above case, stringifying `@_`) if the log level is\nnot active.\n\nThe formatting methods (`infof`, `errorf`, etc.) check the log level for you.\n\nSome logging mechanisms don't support detection of log levels. In these cases\nthe detection methods will always return 1.\n\nIn contrast, the default logging mechanism - Null - will return 0 for all\ndetection methods.\n\n## Log context data\n\n`Log::Any` supports logging context data by exposing the `context`\nhashref. All the key/value pairs added to this hash will be printed\nwith every log message. You can localize the data so that it will be\nremoved again automatically at the end of the block:\n\n    $log-\u003econtext-\u003e{directory} = $dir;\n    for my $file (glob \"$dir/*\") {\n        local $log-\u003econtext-\u003e{file} = basename($file);\n        $log-\u003ewarn(\"Can't read file!\") unless -r $file;\n    }\n\nThis will produce the following line:\n\n    Can't read file! {directory =\u003e '/foo',file =\u003e 'bar'}\n\nIf the configured [Log::Any::Adapter](https://metacpan.org/pod/Log%3A%3AAny%3A%3AAdapter) does not support structured\ndata, the context hash will be converted to a string using\n[Data::Dumper](https://metacpan.org/pod/Data%3A%3ADumper), and will be appended to the log message.\n\n## Setting an alternate default logger\n\nWhen no other adapters are configured for your logger, `Log::Any`\nuses the `default_adapter`. To choose something other than Null as\nthe default, either set the `LOG_ANY_DEFAULT_ADAPTER` environment\nvariable, or pass it as a parameter when loading `Log::Any`\n\n    use Log::Any '$log', default_adapter =\u003e 'Stderr';\n\nThe name of the default class follows the same rules as used by [Log::Any::Adapter](https://metacpan.org/pod/Log%3A%3AAny%3A%3AAdapter).\n\nTo pass arguments to the default adapter's constructor, use an arrayref:\n\n    use Log::Any '$log', default_adapter =\u003e [ 'File' =\u003e '/var/log/mylog.log' ];\n\nWhen a consumer configures their own adapter, the default adapter will be\noverridden. If they later remove their adapter, the default adapter will be\nused again.\n\n## Configuring the proxy\n\nAny parameters passed on the import line or via the `get_logger` method\nare passed on to the [Log::Any::Proxy](https://metacpan.org/pod/Log%3A%3AAny%3A%3AProxy) constructor.\n\n    use Log::Any '$log', filter =\u003e \\\u0026myfilter;\n\n## Testing\n\n[Log::Any::Test](https://metacpan.org/pod/Log%3A%3AAny%3A%3ATest) provides a mechanism to test code that uses `Log::Any`.\n\n# CONSUMING LOGS (FOR APPLICATIONS)\n\nLog::Any provides modules with a [Log::Any::Proxy](https://metacpan.org/pod/Log%3A%3AAny%3A%3AProxy) object, which is the log\nproducer.  To consume its output and direct it where you want (a file, the\nscreen, syslog, etc.), you use [Log::Any::Adapter](https://metacpan.org/pod/Log%3A%3AAny%3A%3AAdapter) along with a\ndestination-specific subclass.\n\nFor example, to send output to a file via [Log::Any::Adapter::File](https://metacpan.org/pod/Log%3A%3AAny%3A%3AAdapter%3A%3AFile), your\napplication could do this:\n\n    use Log::Any::Adapter ('File', '/path/to/file.log');\n\nSee the [Log::Any::Adapter](https://metacpan.org/pod/Log%3A%3AAny%3A%3AAdapter) documentation for more details.\n\nTo detect if a consumer exists, use `Log::Any-\u003ehas_consumer`.\n\n# Q \u0026 A\n\n- Isn't Log::Any just yet another logging mechanism?\n\n    No. `Log::Any` does not include code that knows how to log to a particular\n    place (file, screen, etc.) It can only forward logging requests to another\n    logging mechanism.\n\n- Why don't you just pick the best logging mechanism, and use and promote it?\n\n    Each of the logging mechanisms have their pros and cons, particularly in terms\n    of how they are configured. For example, log4perl offers a great deal of power\n    and flexibility but uses a global and potentially heavy configuration, whereas\n    [Log::Dispatch](https://metacpan.org/pod/Log%3A%3ADispatch) is extremely configuration-light but doesn't handle\n    categories. There is also the unnamed future logger that may have advantages\n    over either of these two, and all the custom in-house loggers people have\n    created and cannot (for whatever reason) stop using.\n\n- Is it safe for my critical module to depend on Log::Any?\n\n    Our intent is to keep `Log::Any` minimal, and change it only when absolutely\n    necessary. Most of the \"innovation\", if any, is expected to occur in\n    `Log::Any::Adapter`, which your module should not have to depend on (unless it\n    wants to direct logs somewhere specific). `Log::Any` has no non-core dependencies.\n\n- Why doesn't Log::Any use _insert modern Perl technique_?\n\n    To encourage CPAN module authors to adopt and use `Log::Any`, we aim to have\n    as few dependencies and chances of breakage as possible. Thus, no `Moose` or\n    other niceties.\n\n# AUTHORS\n\n- Jonathan Swartz \u003cswartz@pobox.com\u003e\n- David Golden \u003cdagolden@cpan.org\u003e\n- Doug Bell \u003cpreaction@cpan.org\u003e\n- Daniel Pittman \u003cdaniel@rimspace.net\u003e\n- Stephen Thirlwall \u003csdt@cpan.org\u003e\n\n# CONTRIBUTORS\n\n- Akron \u003cnils@diewald-online.de\u003e\n- Andrew Grechkin \u003candrew.grechkin@gmail.com\u003e\n- Andrew Hewus Fresh \u0026lt;andrew+github@afresh1.com\u003e\n- bj5004 \u003cbartosz.jakubski@hurra.com\u003e\n- cm-perl \u003ccm-perl@users.noreply.github.com\u003e\n- Jonathan \u0026lt;jjrs.pam+github@gmail.com\u003e\n- Jonathan Rubin \u003cjon.rubin@grantstreet.com\u003e\n- Karen Etheridge \u003cether@cpan.org\u003e\n- Konstantin S. Uvarin \u003ckhedin@gmail.com\u003e\n- Larry Leszczynski \u003clarryl@cpan.org\u003e\n- Lucas Kanashiro \u003ckanashiro.duarte@gmail.com\u003e\n- Maros Kollar \u003cmaros.kollar@geizhals.at\u003e\n- Maxim Vuets \u003cmaxim.vuets@booking.com\u003e\n- mephinet \u003cmephinet@gmx.net\u003e\n- Michael Conrad \u003cmconrad@intellitree.com\u003e\n- Mikko Koivunalho \u003cmikkoi@cpan.org\u003e\n- Nick Tonkin \u003c1nickt@users.noreply.github.com\u003e\n- Paul Durden \u003calabamapaul@gmail.com\u003e\n- Philipp Gortan \u003cphilipp.gortan@apa.at\u003e\n- Phill Legault \u003csaladdayllc@gmail.com\u003e\n- Samuel Ng \u003csamuel.ng@grantstreet.com\u003e\n- Shlomi Fish \u003cshlomif@shlomifish.org\u003e\n- Sven Willenbuecher \u003csven.willenbuecher@kuehne-nagel.com\u003e\n- Tina Müller \u003ccpan2@tinita.de\u003e\n- XSven \u003cXSven@users.noreply.github.com\u003e\n\n# COPYRIGHT AND LICENSE\n\nThis software is copyright (c) 2017 by Jonathan Swartz, David Golden, and Doug Bell.\n\nThis is free software; you can redistribute it and/or modify it under\nthe same terms as the Perl 5 programming language system itself.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpreaction%2Flog-any","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpreaction%2Flog-any","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpreaction%2Flog-any/lists"}