zalora / punyan
Bunyan 的 PHP 实现
Requires
- php: >= 7.0
Requires (Dev)
- codeclimate/php-test-reporter: dev-master
- phpmd/phpmd: dev-master
- phpunit/phpunit: ~5
This package is not auto-updated.
Last update: 2024-09-28 18:31:53 UTC
README
Punyan 是 Bunyan Logger 的 PHP 实现,最初是为 node.js 编写的
需求
- Linux / OS X(也许有人想尝试 Windows?)
- PHP 7.x
- Composer
- NPM
安装
$ composer require zalora/punyan
简洁的日志记录器
{ "writers": [ { "stream": { "url": "/tmp/myproject.log", "filters": [{ "priority": { "priority": "info" } }] } } ] }
$config = [ 'writers' => [ ['stream' => [ 'url' => '/tmp/myproject.log', 'filters' => [ ['priority' => ['priority' => 'info']] ] ]] ] ];
<?php use Zalora\Punyan\Logger; use Zalora\Punyan\ZLog; ZLog::setInstance(new Logger('MyAppName', $config)); ... ZLog::info('Informative log message', ['param1' => 'stuffs']);
$ sudo npm install -g bunyan
$ tail -f /tmp/myproject.log | bunyan -o short -L
Bunyan 实际上是少数几个无需警告或错误即可安装的 npm 模块之一!
配置文件
示例配置是 JSON 格式编写的,只要表示相同的结构,其他格式也可以工作。记录器本身期望一个具有相同结构的数组。
{ "mute": false, "filters": [ { "priority": {"priority": "info", "operator": ">="} } ], "writers": [ { "Stream": { "mute": false, "url": "php://stdout", "filters": [ { "priority": { "priority": "warn" } }, { "ns": { "namespace": "Service", "searchMethod": "contains" } } ] } } ] }
顶级选项
- mute:顶级 mute 会静音整个记录器,writer 中的 mute 仅适用于此特定 writer
- filters:顶级 filter 适用于整个记录器,writer 中的 filter 仅适用于特定 writer
- writers:每个记录器可以有零个或多个 writer(当然,多于零个 writer 更有趣...)
- exceptionHandler:为了确保我们可以屏蔽敏感数据,我们需要实现自己的特殊 exceptionHandler,所以我们使其可配置。想想看,您不想在日志文件中包含密码或其他敏感数据。
过滤器
- 回调
- DiscoBouncer
- NoFilter
- 命名空间
- 优先级
- 正则表达式
要添加过滤器,您必须将此结构添加到过滤器数组中
{ "<filter_name>": { "option1": "value1", "option2": "value2" } }
回调
回调过滤器必须返回(true|false),并将 LogEvent 对象传递以提供一些评估数据。
唯一的选项是
- function:请确保它是可调用的
如果您不返回任何内容,则假定返回 false。当然,这也取决于您确保类已加载或存在自动加载器来执行此操作。
示例
{ "callback": { "function": "MyClass::myStaticMethod" }}
DiscoBouncer
名字已经说明了一切:它将过滤所有内容。这个过滤器没有选项,目前用于单元测试。如果您找到实际用例,请告诉我。我很感兴趣。
示例
{ "discoBouncer": {} }
NoFilter
DiscoBouncer 的相反,允许一切通过。
示例
{ "noFilter": {} }
命名空间(Ns)
此过滤器应用于您的类名(包括命名空间),因此您可以使用它为您的模块分配单独的日志文件。正则表达式在记录器初始化时进行验证。
选项
- namespace:在命名空间中搜索什么
- searchMethod:(可选,默认 'startsWith')以下之一:(startsWith|contains|regexp)
如果您使用 regexp 作为 searchMethod,则 namespace 包含您的正则表达式
示例
这只会接受包含标记 'Service' 的类的日志
{ "ns": { "namespace": "Service", "searchMethod": "contains" } }
我的正则表达式 foo 非常低,对此表示歉意。我希望这个匹配以 Hello 结尾的每个类
{ "ns": { "namespace": "/Hello$/", "searchMethod": "regexp" } }
优先级
优先级过滤器根据优先级进行过滤(惊喜...),例如,如果过滤器级别设置为 'info',则一切从 'info' 开始通过。我想没有太多要解释的。
以下是完整选项列表
- priority:以下之一(trace|debug|info|warn|error|fatal)
- 操作符:(可选,默认 >=) 你不需要修改它...
示例
{ "priority": { "priority": "warn", "operator": ">=" } }
正则表达式
将字段(默认为日志消息)与你的正则表达式模式进行匹配。以下是过滤器的选项
- pattern:(必需)你的正则表达式
- field:(可选,默认 'msg') 在上下文中运行正则表达式的字段。要访问嵌套值,请使用点作为分隔符,例如
request.src
来访问$context['request']['src']
- returnValueOnMissingField:(可选,默认 false) 如果字段不存在,则返回 true 或 false
示例
{ "regexp": { "pattern": "/^https/", "field": "request.url", "returnValueOnMissingField": false } }
匹配所有以 https 开头的 URL,如果没有记录任何 URL,则丢弃日志条目。
写入器
目前只有一个写入器(StreamWriter),在未来的版本中,我将添加几个以支持 FirePHP 和 Slack。每个写入器都有三个选项
- mute (true|false) 默认是 false
- origin (true|false) 默认是 true
- bubble (true|false) 默认是 true
静音
这将(明显)静音写入器并抑制任何潜在的输出
原始
原始添加一个包含日志调用触发位置信息的数组,它包含以下字段
- file
- line
- class
- function
例如,对于命名空间过滤器这是必需的。如果你将原始设置为 false 并添加 Ns-过滤器,则过滤器将始终返回 false。
冒泡
一旦写入器记录了消息,则日志事件不会被发送到其他写入器。示例
{ "filters": [ { "priority": { "priority": "info" } } ], "writers": [ { "Stream": { "origin": true, "bubble": false, "url": "services.log", "filters": [ { "ns": { "namespace": "Service", "searchMethod": "contains" } } ] } }, { "Stream": { "origin": true, "url": "common.log", "filters": [] } } ] }
The services.log 保留所有来自包含单词 Service 的类名的类的日志事件。如果没有冒泡,则日志消息将出现在两个文件中,因为 common.log 的流写入器没有任何过滤器。所以冒泡可以用来防止重复的日志消息。请注意,当你使用冒泡时,定义你的写入器的顺序很重要!
免责声明:我从 Monolog 借用了“冒泡”这个词
StreamWriter
StreamWriter 支持所有可写流(https://php.ac.cn/manual/en/wrappers.php),例如
- php://memory
- file:///tmp/myproject.log
- php://stdout
选项
- url:你想要写入(追加)到的 url
- filters:过滤器是可选的,但至少必须存在一个空数组
- mute:(可选,默认 false) 与每个写入器一样,它可以被静音
在初始化过程中将打开流,因此对于文件,你可以很早就知道它是否可写
处理器
我又从 Monolog 借用了这个名字,因为我找不到更好的名字...它们也做同样的事情:为每个日志事件添加额外的数据。
当然你可以手动做这件事,但这需要很多工作,并且会让代码变得混乱,因为即使日志消息本身被过滤掉,它也会被执行。所以你将这段代码移动到处理器中,并将其附加到写入器。从那时起,它将自动收集所有所需的信息。
处理器有一个共同字段
- onDemand (true|false) 默认是 false
附加数据存储在键 'proc' 下,该键在 Zalora\Punyan\IProcessor
中定义。
示例
{ "Web": { "onDemand": true }}
或 { "Web": { }}
Web 处理器
以下数据添加到每个日志事件的 proc 数组中
- url:
$_SERVER['REQUEST_URI']
- ip:
$_SERVER['REMOTE_ADDR']
- http_method:
$_SERVER['REQUEST_METHOD']
- server:
$_SERVER['SERVER_NAME']
- referrer:
$_SERVER['HTTP_REFERER']
已知问题
- 仅支持 Bunyan 格式;这并不是真正的问题,而是一个设计决策。如果有人感兴趣,我可能会放宽这个限制,以便支持其他基于 JSON 的服务...
常见问题解答
为什么要重新发明轮子?
实际上,我没有找到我喜欢且不实现PSR-3接口的日志记录器。最初我以为为Monolog实现一个格式化器应该可以解决问题,但是日志级别匹配不正确,使用映射看起来太像黑客手段了。
由于我们想使用bunyan项目提供的工具,我们必须保持格式兼容。这里又有另一个PHP日志记录器。
计划是什么?
配置存储
为了更改日志级别,你必须更改文件,甚至更糟糕的是更改代码。我想提供一个小的命令行程序,该程序可以在无需可写文件或重新部署的情况下更改配置。这可以通过将配置存储在键值存储中实现
新过滤器
- 速率限制:关闭冒泡功能后,你可以避免在夜间发送五亿封电子邮件;-)
- 采样器:过滤掉一定比例的事件
新写入器
- AMQP:将日志发送到RabbitMQ
- Slack:你最喜欢的消息传递应用
- FirePHP:在开发期间将日志事件发送到浏览器
- Responsys:通过电子邮件发送重要的日志(注意速率限制...)
- New Relic:你最喜欢的应用程序监控工具
- Redis:将日志持久化到Redis列表