5
5
namespace Gokure \HttpLogger ;
6
6
7
7
use Hyperf \Contract \ConfigInterface ;
8
- use Hyperf \Utils \ Context ;
9
- use Psr \ Container \ ContainerInterface ;
8
+ use Hyperf \Logger \ LoggerFactory ;
9
+ use Monolog \ Level ;
10
10
use Psr \Http \Message \ResponseInterface ;
11
11
use Psr \Http \Message \ServerRequestInterface ;
12
+ use Psr \Log \LoggerInterface ;
13
+ use function \Hyperf \Collection \collect ;
12
14
13
15
class HttpLogger
14
16
{
15
- protected const HYPERF_START = __CLASS__ . ' .HYPERF_START ' ;
17
+ protected LoggerInterface $ logger ;
16
18
17
- /**
18
- * @var ContainerInterface
19
- */
20
- protected $ container ;
19
+ protected array $ options ;
21
20
22
- /**
23
- * @var array
24
- */
25
- protected $ options ;
26
-
27
- public function __construct (ContainerInterface $ container )
28
- {
29
- $ this ->container = $ container ;
30
- $ options = $ this ->container ->get (ConfigInterface::class)->get ('http_logger ' , []);
31
- $ this ->options = $ this ->normalizeOptions ($ options );
32
- }
33
-
34
- public function setUp (): void
21
+ public function __construct (LoggerFactory $ factory , ConfigInterface $ config )
35
22
{
36
- Context::set (static ::HYPERF_START , microtime (true ));
23
+ $ this ->options = $ this ->normalizeOptions ($ config ->get ('http_logger ' , []));
24
+ $ name = $ this ->options ['logger ' ]['name ' ] ?? 'hyperf ' ;
25
+ $ group = $ this ->options ['logger ' ]['group ' ] ?? 'default ' ;
26
+ $ this ->logger = $ factory ->get ($ name , $ group );
37
27
}
38
28
39
- public function record (ResponseInterface $ response , ServerRequestInterface $ request, $ level = Logger:: INFO ): void
29
+ public function record (\ Throwable | ResponseInterface $ response , ServerRequestInterface $ request ): void
40
30
{
41
- if (!$ this ->shouldRecord ($ response , $ request )) {
31
+ if (! $ this ->shouldRecord ($ response , $ request )) {
42
32
return ;
43
33
}
44
34
@@ -58,43 +48,56 @@ public function record(ResponseInterface $response, ServerRequestInterface $requ
58
48
})->toArray (),
59
49
]);
60
50
61
- $ context ['response ' ] = array_filter ([
62
- 'body ' => (string )$ response ->getBody (),
63
- ]);
51
+ if ($ response instanceof \Throwable) {
52
+ $ context ['exception ' ] = [
53
+ 'message ' => $ response ->getMessage (),
54
+ 'trace ' => $ response ->getTraceAsString (),
55
+ ];
56
+ } else {
57
+ $ context ['response ' ] = array_filter ([
58
+ 'body ' => (string )$ response ->getBody (),
59
+ ]);
60
+ }
64
61
}
65
62
66
- $ requestTime = microtime (true ) - Context::get (static ::HYPERF_START , microtime (true ));
67
- Context::destroy (static ::HYPERF_START );
63
+ $ server = $ request ->getServerParams ();
64
+ if (isset ($ server ['request_time_float ' ])) {
65
+ $ startTime = $ server ['request_time_float ' ];
66
+ $ executeTime = number_format (microtime (true ) - $ startTime , 3 );
67
+ } else {
68
+ $ executeTime = '- ' ;
69
+ }
68
70
69
71
// "GET /path HTTP/1.1" 200 0.026 "User-Agent"
70
72
$ message = sprintf ('"%s %s HTTP/%s" %s %s "%s" ' ,
71
73
$ request ->getMethod (),
72
74
$ request ->getRequestTarget (),
73
75
$ request ->getProtocolVersion (),
74
- $ response ->getStatusCode (),
75
- number_format ( $ requestTime , 3 ) ,
76
- $ request ->getHeaderLine ('User-Agent ' )
76
+ $ response instanceof ResponseInterface ? $ response ->getStatusCode () : ' - ' ,
77
+ $ executeTime ,
78
+ $ request ->getHeaderLine ('user-agent ' )
77
79
);
78
80
79
- if ($ this ->options ['long_request_time ' ] > 0 && $ requestTime >= $ this ->options ['long_request_time ' ]) {
80
- $ logger = $ this ->container ->get (LoggerFactory::class)->get ('http-slow ' );
81
- } else {
82
- $ logger = $ this ->container ->get (LoggerFactory::class)->get ('http ' );
83
- }
84
-
85
- $ logger ->log ($ level , $ message , $ context );
81
+ $ level = $ response instanceof \Throwable ? Level::Error : Level::Info;
82
+ $ this ->logger ->log ($ level , $ message , $ context );
86
83
}
87
84
88
- protected function shouldRecord (ResponseInterface $ response , ServerRequestInterface $ request ): bool
85
+ protected function shouldRecord (\ Throwable | ResponseInterface $ response , ServerRequestInterface $ request ): bool
89
86
{
90
- return !$ this ->isSuccessful ($ response ) ||
91
- $ this ->options ['allowed_methods ' ] === true ||
92
- in_array (strtoupper ($ request ->getMethod ()), $ this ->options ['allowed_methods ' ], true );
87
+ return $ response instanceof \Throwable ||
88
+ ! $ this ->isSuccessful ($ response ) ||
89
+ (
90
+ (
91
+ $ this ->options ['allowed_methods ' ] === true ||
92
+ in_array (strtoupper ($ request ->getMethod ()), $ this ->options ['allowed_methods ' ], true )
93
+ ) && $ this ->options ['bypass_function ' ]($ response , $ request ) !== true
94
+ );
93
95
}
94
96
95
- protected function shouldRecordContext (ResponseInterface $ response , ServerRequestInterface $ request ): bool
97
+ protected function shouldRecordContext (\ Throwable | ResponseInterface $ response , ServerRequestInterface $ request ): bool
96
98
{
97
- return !$ this ->isSuccessful ($ response ) ||
99
+ return $ response instanceof \Throwable ||
100
+ ! $ this ->isSuccessful ($ response ) ||
98
101
$ this ->options ['allowed_context_methods ' ] === true ||
99
102
in_array (strtoupper ($ request ->getMethod ()), $ this ->options ['allowed_context_methods ' ], true );
100
103
}
@@ -109,28 +112,18 @@ protected function normalizeOptions(array $options = []): array
109
112
$ options += [
110
113
'allowed_methods ' => ['* ' ],
111
114
'allowed_context_methods ' => ['POST ' , 'PUT ' , 'PATCH ' , 'DELETE ' ],
112
- 'slow_request_log ' => false ,
113
- 'long_request_time ' => 3.0 ,
114
115
'logger ' => [
115
- 'handler ' => [
116
- 'class ' => \Monolog \Handler \StreamHandler::class,
117
- 'constructor ' => [
118
- 'stream ' => BASE_PATH . '/runtime/logs/hyperf.log ' ,
119
- ],
120
- ],
121
- 'formatter ' => [
122
- 'class ' => \Monolog \Formatter \LineFormatter::class,
123
- 'constructor ' => [
124
- 'format ' => null ,
125
- 'dateFormat ' => 'Y-m-d H:i:s ' ,
126
- 'allowInlineLineBreaks ' => false ,
127
- ],
128
- ],
116
+ 'name ' => 'hyperf ' ,
117
+ 'group ' => 'default ' ,
129
118
],
130
119
];
131
120
121
+ if (! isset ($ options ['bypass_function ' ])) {
122
+ $ options ['bypass_function ' ] = function () {};
123
+ }
124
+
132
125
foreach (['allowed_methods ' , 'allowed_context_methods ' ] as $ key ) {
133
- if (!is_array ($ options [$ key ])) {
126
+ if (! is_array ($ options [$ key ])) {
134
127
throw new \RuntimeException ('Http Logger config ` ' . $ key . '` should be an array. ' );
135
128
}
136
129
}
0 commit comments