Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 49 |
|
0.00% |
0 / 3 |
CRAP | |
0.00% |
0 / 1 |
MultiSearchRequestLog | |
0.00% |
0 / 49 |
|
0.00% |
0 / 3 |
210 | |
0.00% |
0 / 1 |
getLogVariables | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
42 | |||
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 | // @phan-suppress-next-line PhanImpossibleCondition |
39 | if ( !empty( $lines ) ) { |
40 | $vars += $this->extractRequestVariables( |
41 | array_slice( $lines, 0, 2 ) |
42 | ); |
43 | } |
44 | |
45 | $responseData = $this->response->getData(); |
46 | if ( !empty( $responseData['responses'] ) ) { |
47 | // Have to use + $vars, rather than +=, to |
48 | // allow 'suggestion' returned from here to |
49 | // override 'suggestion' provided by $this->extra |
50 | $vars = $this->extractResponseVariables( |
51 | reset( $responseData['responses'] ) |
52 | ) + $vars; |
53 | } |
54 | |
55 | // in case of failures from Elastica |
56 | if ( isset( $responseData['message'] ) ) { |
57 | $vars['error_message'] = $responseData['message']; |
58 | } |
59 | |
60 | return $vars; |
61 | } |
62 | |
63 | /** |
64 | * @return array[] |
65 | */ |
66 | public function getRequests() { |
67 | if ( !$this->request || !$this->response ) { |
68 | // we don't actually know at this point how many searches there were, |
69 | // or how many results to return...so just bail and return nothing |
70 | return []; |
71 | } |
72 | |
73 | $responseData = $this->response->getData(); |
74 | if ( !$responseData || !isset( $responseData['responses'] ) ) { |
75 | $message = $responseData['message'] ?? 'no message'; |
76 | LoggerFactory::getInstance( 'CirrusSearch' )->warning( |
77 | 'Elasticsearch response does not have any data. {response_message}', |
78 | [ 'response_message' => $message ] |
79 | ); |
80 | return []; |
81 | } |
82 | |
83 | // In a multi-search instance the plain string, as sent to elasticsearch, |
84 | // is returned by Request::getData(). Each single request is represented |
85 | // by two lines, first a metadata line about the request and second the |
86 | // actual query. |
87 | $lines = explode( "\n", trim( $this->request->getData(), "\n" ) ); |
88 | $requestData = array_chunk( $lines, 2 ); |
89 | |
90 | if ( count( $requestData ) !== count( $responseData['responses'] ) ) { |
91 | // The world has ended...:( |
92 | // @todo add more context. |
93 | throw new \RuntimeException( 'Request and response data does not match' ); |
94 | } |
95 | |
96 | $meta = [ |
97 | 'queryType' => $this->queryType, |
98 | 'tookMs' => $this->getTookMs(), |
99 | ] + $this->extra; |
100 | $requests = []; |
101 | foreach ( $responseData['responses'] as $singleResponseData ) { |
102 | $vars = $this->extractRequestVariables( array_shift( $requestData ) ) + |
103 | $this->extractResponseVariables( $singleResponseData ); |
104 | $vars['hits'] = $this->extractHits( $singleResponseData ); |
105 | // + $meta must come *after* extractResponseVariables, because |
106 | // items like 'suggestion' override data provided in $this->extra |
107 | $requests[] = $vars + $meta; |
108 | } |
109 | |
110 | return $requests; |
111 | } |
112 | |
113 | /** |
114 | * @param array $requestData |
115 | * @return array |
116 | */ |
117 | protected function extractRequestVariables( $requestData ) { |
118 | // @todo error check decode |
119 | $meta = json_decode( $requestData[0], true ); |
120 | $query = json_decode( $requestData[1], true ); |
121 | |
122 | return [ |
123 | // @phan-suppress-next-line PhanTypeArraySuspiciousNullable |
124 | 'index' => implode( ',', $meta['index'] ), |
125 | ] + parent::extractRequestVariables( $query ); |
126 | } |
127 | } |