-
Notifications
You must be signed in to change notification settings - Fork 89
Expand file tree
/
Copy pathHttpLog.xml
More file actions
152 lines (132 loc) · 9.53 KB
/
Copy pathHttpLog.xml
File metadata and controls
152 lines (132 loc) · 9.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<?xml version="1.0" encoding="UTF-8"?>
<!--
This software is in the public domain under CC0 1.0 Universal plus a
Grant of Patent License.
To the extent possible under law, the author(s) have dedicated all
copyright and related and neighboring rights to this software to the
public domain worldwide. This software is distributed without any
warranty.
You should have received a copy of the CC0 Public Domain Dedication
along with this software (see the LICENSE.md file). If not, see
<http://creativecommons.org/publicdomain/zero/1.0/>.
-->
<screen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/xml-screen-2.1.xsd"
default-menu-title="Http Log" default-menu-index="20">
<actions>
<set field="indexName" from="indexName ?: 'moqui_http_log'"/>
<set field="pageIndex" from="(pageIndex?:'0') as int"/>
<set field="pageSize" from="(pageSize?:'100') as int"/>
<!-- default to last 7 days, always have a time range to avoid massive and slow results -->
<if condition="!tsPeriod_period && !tsPeriod_from && !tsPeriod_thru">
<set field="tsPeriod_period" from="tsPeriod_period ?: '7d'"/>
<set field="tsPeriod_poffset" from="tsPeriod_poffset ?: '-1'"/>
</if>
<set field="tsList" from="ec.user.getPeriodRange('tsPeriod', context)"/>
<script><![CDATA[
/* useful docs for query API: https://www.elastic.co/guide/reference/api/search/uri-request/ */
import org.moqui.context.ExecutionContext
ExecutionContext ec = context.ec
def elasticClient = ec.factory.elastic.getClient("logger") ?: ec.factory.elastic.getClient("default")
if (elasticClient == null) {
ec.message.addError("Could not find ElasticClient for cluster name logger or default")
return
}
int fromOffset = pageIndex * pageSize
int sizeLimit = pageSize
// build query string
if (tsList != null && (tsList.get(0) != null || tsList.get(1) != null)) {
actualQuery = '@timestamp:[' + (tsList.get(0) != null ? tsList.get(0).time : '*') + ' TO ' + (tsList.get(1) != null ? tsList.get(1).time : '*') + ']'
if (queryString) actualQuery = actualQuery + ' AND (' + queryString + ')'
} else {
actualQuery = queryString ?: '*'
}
// query string: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html
// had time_zone but shouldn't matter using epoch_millis format and causes issues sometimes: time_zone:TimeZone.default.getID()
Map queryMap = [query_string:[query:actualQuery, lenient:true]]
Map searchMap = [query:queryMap, from:fromOffset, size:sizeLimit, track_total_hits:true, sort:[['@timestamp':'desc']]]
// validate the query
// TODO: consider pulling error message from ElasticSearch, but they are pretty ugly
Map validateRespMap = elasticClient.validateQuery((String) indexName, queryMap, true)
if (validateRespMap != null) {
ec.message.addMessage("Invalid search: ${queryString}", "danger")
List explanations = (List) validateRespMap.explanations
if (explanations) for (Map explanation in explanations) ec.message.addMessage(explanation.error, "danger")
return
}
// get the search hits
Map resultMap = elasticClient.search((String) indexName, searchMap)
Map hitsMap = (Map) resultMap.hits
List<Map> hitsList = (List<Map>) hitsMap.hits
documentList = []
for (Map hit in hitsList) {
Map document = (Map) hit._source
document._id = hit._id
documentList.add(document)
}
// get the total search count
documentListCount = hitsMap.total.value
// calculate the pagination values
documentListPageIndex = pageIndex
documentListPageSize = pageSize
documentListPageMaxIndex = ((BigDecimal) documentListCount - 1).divide(documentListPageSize, 0, BigDecimal.ROUND_DOWN) as int
documentListPageRangeLow = documentListPageIndex * documentListPageSize + 1
documentListPageRangeHigh = (documentListPageIndex * documentListPageSize) + documentListPageSize
if (documentListPageRangeHigh > documentListCount) documentListPageRangeHigh = documentListCount
// show in reverse order, but still higher pages going back in time
documentList = documentList.reverse()
]]></script>
</actions>
<widgets>
<link url="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax"
url-type="plain" link-type="anchor" target-window="_blank" text="Query String Reference"/>
<form-single name="SearchOptions" transition=".">
<field name="indexName"><default-field title=""><text-line size="12" default-value="moqui_logs"/></default-field></field>
<field name="queryString"><default-field title=""><text-line size="60"/></default-field></field>
<field name="tsPeriod"><default-field title=""><date-period time="true"/></default-field></field>
<field name="submitButton"><default-field title="Search"><submit/></default-field></field>
<field-layout><field-row-big><field-ref name="indexName"/><field-ref name="queryString"/><field-ref name="tsPeriod"/><field-ref name="submitButton"/></field-row-big></field-layout>
</form-single>
<label text="Date Range: ${ec.l10n.format(tsList.get(0), 'yyyy-MM-dd HH:mm:ss.SSS') ?: '*'} to ${ec.l10n.format(tsList.get(1), 'yyyy-MM-dd HH:mm:ss.SSS') ?: '*'}" type="p"/>
<label text="Full query: ${actualQuery}" type="p"/>
<!-- show messages, mainly for 'Invalid search...' message -->
<section-iterate name="messageInfos" list="ec.message.messageInfos" entry="messageInfo"><widgets>
<container><label text="${messageInfo.message}" type="strong" style="text-${messageInfo.typeString}"/></container>
</widgets></section-iterate>
<form-list name="HttpLogMessageDocuments" list="documentList" paginate="true" paginate-always-show="true" skip-form="true">
<row-actions>
<set field="levelStyle" from="'ERROR'.equals(level) ? 'text-danger' : ('WARN'.equals(level) ? 'text-warning' : ('INFO'.equals(level) ? 'text-success' : ''))"/>
</row-actions>
<field name="@timestamp"><default-field container-style="text-nowrap ${levelStyle}">
<display text="${ec.l10n.format(new Timestamp(context.get('@timestamp')), 'yyyy-MM-dd HH:mm:ss.SSS')}" encode="false"/></default-field></field>
<field name="remote_ip"><default-field><display/></default-field></field>
<field name="remote_user"><default-field><display/></default-field></field>
<field name="content_type"><default-field><display/></default-field></field>
<field name="request_method"><default-field><display/></default-field></field>
<field name="request_scheme"><default-field><display/></default-field></field>
<field name="request_host"><default-field><display/></default-field></field>
<field name="request_path"><default-field><display/></default-field></field>
<field name="request_query">
<conditional-field condition="request_query != null && request_query.length() > 80">
<display text="${request_query.substring(0, 80)} "/>
<container-dialog id="ViewRequestQuery" button-text="All" width="800"><label text="${request_query}"/></container-dialog>
</conditional-field>
<default-field><display/></default-field>
</field>
<field name="http_version"><default-field><display/></default-field></field>
<field name="response"><default-field><display/></default-field></field>
<field name="time_initial_ms"><default-field><display/></default-field></field>
<field name="time_final_ms"><default-field><display/></default-field></field>
<field name="bytes"><default-field><display/></default-field></field>
<field name="referrer"><default-field><display/></default-field></field>
<field name="agent"><default-field><display/></default-field></field>
<field name="session"><default-field><display/></default-field></field>
<field name="visitor_id"><default-field><display/></default-field></field>
<form-list-column><field-ref name="@timestamp"/><field-ref name="time_initial_ms"/><field-ref name="time_final_ms"/></form-list-column>
<form-list-column><field-ref name="remote_ip"/><field-ref name="remote_user"/></form-list-column>
<form-list-column><field-ref name="request_host"/><field-ref name="request_method"/><field-ref name="request_scheme"/></form-list-column>
<form-list-column><field-ref name="http_version"/><field-ref name="response"/><field-ref name="bytes"/></form-list-column>
<form-list-column><field-ref name="referrer"/><field-ref name="request_path"/><field-ref name="request_query"/></form-list-column>
<form-list-column><field-ref name="session"/><field-ref name="visitor_id"/><field-ref name="agent"/></form-list-column>
</form-list>
</widgets>
</screen>