Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 48 |
|
0.00% |
0 / 3 |
CRAP | |
0.00% |
0 / 1 |
MultiSearchRequestLog | |
0.00% |
0 / 48 |
|
0.00% |
0 / 3 |
182 | |
0.00% |
0 / 1 |
getLogVariables | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
30 | |||
getRequests | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
56 | |||
extractRequestVariables | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace CirrusSearch; |
4 | |
5 | use MediaWiki\Logger\LoggerFactory; |
6 | |
7 | /** |
8 | * Extending from SearchRequestLog doesn't quite feel right, but there |
9 | * is a good amount of shared code. think about best way. |
10 | */ |
11 | class MultiSearchRequestLog extends SearchRequestLog { |
12 | |
13 | /** |
14 | * Not sure what's best to return here, primarily we need whatever |
15 | * would be interesting when looking at error logging. For now this |
16 | * just generates a context for the first request and ignores the |
17 | * existence of the rest. |
18 | * |
19 | * Basically this is known to be wrong, but not sure what to do instead. |
20 | * |
21 | * @return array |
22 | */ |
23 | public function getLogVariables() { |
24 | $vars = [ |
25 | 'queryType' => $this->queryType, |
26 | 'tookMs' => $this->getTookMs(), |
27 | ] + $this->extra; |
28 | |
29 | if ( !$this->request || !$this->response ) { |
30 | return $vars; |
31 | } |
32 | |
33 | // In a multi-search instance the plain string, as sent to elasticsearch, |
34 | // is returned by Request::getData(). Each single request is represented |
35 | // by two lines, first a metadata line about the request and second the |
36 | // actual query. |
37 | $lines = explode( "\n", trim( $this->request->getData(), "\n" ) ); |
38 | $vars += $this->extractRequestVariables( |
39 | array_slice( $lines, 0, 2 ) |
40 | ); |
41 | |
42 | $responseData = $this->response->getData(); |
43 | if ( !empty( $responseData['responses'] ) ) { |
44 | // Have to use + $vars, rather than +=, to |
45 | // allow 'suggestion' returned from here to |
46 | // override 'suggestion' provided by $this->extra |
47 | $vars = $this->extractResponseVariables( |
48 | reset( $responseData['responses'] ) |
49 | ) + $vars; |
50 | } |
51 | |
52 | // in case of failures from Elastica |
53 | if ( isset( $responseData['message'] ) ) { |
54 | $vars['error_message'] = $responseData['message']; |
55 | } |
56 | |
57 | return $vars; |
58 | } |
59 | |
60 | /** |
61 | * @return array[] |
62 | */ |
63 | public function getRequests() { |
64 | if ( !$this->request || !$this->response ) { |
65 | // we don't actually know at this point how many searches there were, |
66 | // or how many results to return...so just bail and return nothing |
67 | return []; |
68 | } |
69 | |
70 | $responseData = $this->response->getData(); |
71 | if ( !$responseData || !isset( $responseData['responses'] ) ) { |
72 | $message = $responseData['message'] ?? 'no message'; |
73 | LoggerFactory::getInstance( 'CirrusSearch' )->warning( |
74 | 'Elasticsearch response does not have any data. {response_message}', |
75 | [ 'response_message' => $message ] |
76 | ); |
77 | return []; |
78 | } |
79 | |
80 | // In a multi-search instance the plain string, as sent to elasticsearch, |
81 | // is returned by Request::getData(). Each single request is represented |
82 | // by two lines, first a metadata line about the request and second the |
83 | // actual query. |
84 | $lines = explode( "\n", trim( $this->request->getData(), "\n" ) ); |
85 | $requestData = array_chunk( $lines, 2 ); |
86 | |
87 | if ( count( $requestData ) !== count( $responseData['responses'] ) ) { |
88 | // The world has ended...:( |
89 | // @todo add more context. |
90 | throw new \RuntimeException( 'Request and response data does not match' ); |
91 | } |
92 | |
93 | $meta = [ |
94 | 'queryType' => $this->queryType, |
95 | 'tookMs' => $this->getTookMs(), |
96 | ] + $this->extra; |
97 | $requests = []; |
98 | foreach ( $responseData['responses'] as $singleResponseData ) { |
99 | $vars = $this->extractRequestVariables( array_shift( $requestData ) ) + |
100 | $this->extractResponseVariables( $singleResponseData ); |
101 | $vars['hits'] = $this->extractHits( $singleResponseData ); |
102 | // + $meta must come *after* extractResponseVariables, because |
103 | // items like 'suggestion' override data provided in $this->extra |
104 | $requests[] = $vars + $meta; |
105 | } |
106 | |
107 | return $requests; |
108 | } |
109 | |
110 | /** |
111 | * @param array $requestData |
112 | * @return array |
113 | */ |
114 | protected function extractRequestVariables( $requestData ) { |
115 | // @todo error check decode |
116 | $meta = json_decode( $requestData[0], true ); |
117 | $query = json_decode( $requestData[1], true ); |
118 | |
119 | return [ |
120 | // @phan-suppress-next-line PhanTypeArraySuspiciousNullable |
121 | 'index' => implode( ',', $meta['index'] ), |
122 | ] + parent::extractRequestVariables( $query ); |
123 | } |
124 | } |