Skip to content

Commit

Permalink
Log viewer and fix when downloading csv file (#604)
Browse files Browse the repository at this point in the history
* Parson json to plain text

* Add implicit sort at init

* Switch to sort by timestamp

* Show box with logs

* Fix when downloading csv file

* Fix firts load of logs content

* Updated changelog

* Add new logs when bottom is reached

* Log viewer improvements

* minor fix

* Fix typo
  • Loading branch information
adri9valle authored and Jesús Ángel committed Mar 12, 2019
1 parent 8e75830 commit c263392
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 90 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ All notable changes to the Wazuh app for Splunk project will be documented in th
- Redisign configuration view ([#597](https://github.com/wazuh/wazuh-splunk/pull/597)).
- Updated autocomplete list in DevTools ([#538](https://github.com/wazuh/wazuh-splunk/pull/538)).
- Modularize some functions ([#601](https://github.com/wazuh/wazuh-splunk/pull/601)).
- Show logs in a text box ([#604](https://github.com/wazuh/wazuh-splunk/pull/604)).

### Fixed

Expand All @@ -70,6 +71,7 @@ All notable changes to the Wazuh app for Splunk project will be documented in th
- Change the selected index ([#580](https://github.com/wazuh/wazuh-splunk/pull/580)).
- More descriptive error when savinga file and get an error ([#601](https://github.com/wazuh/wazuh-splunk/pull/601)).
- Show success message when group configuration is saved ([#601](https://github.com/wazuh/wazuh-splunk/pull/601)).
- Error when trying to download a CSV file ([#604](https://github.com/wazuh/wazuh-splunk/pull/604)).


- Properly handling long messages on notifier service, until now, they were using out of the card space, also we replaced some API messages with more meaningful messages ([#570](https://github.com/wazuh/wazuh-splunk/pull/570)).
Expand Down
13 changes: 6 additions & 7 deletions SplunkAppForWazuh/appserver/controllers/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,14 @@ def csv(self, **kwargs):
parsed_filters.pop(key, None)
filters.update(parsed_filters)

the_id = kwargs['_key']
the_id = kwargs['id']
api = self.db.get(the_id)
opt_username = api[0]["userapi"]
opt_password = api[0]["passapi"]
opt_base_url = api[0]["url"]
opt_base_port = api[0]["portapi"]
api = jsonbak.loads(api)
opt_username = api["data"]["userapi"]
opt_password = api["data"]["passapi"]
opt_base_url = api["data"]["url"]
opt_base_port = api["data"]["portapi"]
opt_endpoint = kwargs['path']
del kwargs['_key']
del kwargs['path']
url = opt_base_url + ":" + opt_base_port
auth = requestsbak.auth.HTTPBasicAuth(opt_username, opt_password)
verify = False
Expand Down
8 changes: 8 additions & 0 deletions SplunkAppForWazuh/appserver/static/css/styles/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@
padding-left: 8px
}

.wz-padding-left-15 {
padding-left: 15px
}

.wz-padding-left-20 {
padding-left: 20px
}

.wz-padding-top-7 {
padding-top: 7px;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,61 +11,77 @@
<div ng-show="!loading" layout="column" layout-padding>
<span class="font-size-18">
<i class="fa fa-fw fa-pencil-square-o" aria-hidden="true"></i> Logs</span>
<span>Review the logs of all Wazuh manager daemons</span>
</div>
<!-- End headline -->

<!-- Filters and Realtime button section -->
<div ng-show="!loading" layout="row" layout-align="start start" class="wz-margin-left-10">

<select class="input input-dropdown" flex id="levelBox" ng-disabled="realtime" ng-model="type_log" placeholder="Log level" class="md-no-underline" ng-change="filter({name:'type_log',value:type_log})" aria-label="Logs level">
<option value="all">All log levels</option>
<option value="info">Info</option>
<option value="error">Error</option>
<option value="warning">Warning</option>
<option value="critical">Critical</option>
<option value="debug">Debug</option>
</select>

<select flex ng-show='nodeList && nodeList.length' class="input input-dropdown wz-margin-left-10" id="categoryBox" ng-model="selectedNode" ng-change="changeNode(selectedNode)" aria-label="Logs category">
<option ng-repeat="node in nodeList" value="{{node}}">{{node}}</option>
</select>

<select class="input input-dropdown wz-margin-left-10" flex id="categoryBox" ng-disabled="realtime" ng-model="category" ng-change="filter({name:'category',value:category})" aria-label="Logs category" >
<option value="all">All daemons</option>
<option ng-repeat="daemon in daemons | orderObjectBy: 'title'" value="{{daemon.title}}">{{daemon.title}}</option>
</select>

<!-- White space between filters and Realtime button -->
<span flex></span>

<md-button ng-if="!realtime" class="wz-button md-raised md-primary wz-margin-right-15" style='margin-top:-4px;' ng-click="playRealtime()" aria-label="Play realtime button">
<i class="fa fa-play fa-fw" aria-hidden="true"></i>
Play realtime
</md-button>
<md-button ng-if="realtime" class="wz-button md-raised md-primary wz-margin-right-15" style='margin-top:-4px;' ng-click="stopRealtime()" aria-label="Stop realtime button">
<i class="fa fa-stop fa-fw" aria-hidden="true"></i>
Stop realtime
</md-button>
</div>

<div layout="row">

<input flex placeholder="Filter logs..." ng-model="custom_search" type="text" class="kuiLocalSearchInput ng-empty ng-pristine ng-scope ng-touched ng-valid wz-margin-top-4 height-36 wz-margin-left-10" aria-invalid="false" wz-enter="search(custom_search)">
<button type="submit" aria-label="Search" class="kuiLocalSearchButton height-36 wz-margin-top-4 wz-margin-right-16" ng-click="search(custom_search)">
<span class="fa fa-search" aria-hidden="true"></span>
</button>
</div>
<!-- End Filters and Realtime button section -->

<!-- Logs table section -->
<div layout="row" layout-padding ng-if="logsPath">
<wazuh-table flex extra-limit="100" path="logsPath" keys="['timestamp',{value:'tag',size:2},'level',{value:'description',size:4,nosortable:true}]"
<span>Review the logs of all Wazuh manager daemons</span>
</div>
<!-- End headline -->

<!-- Filters and Realtime button section -->
<div ng-show="!loading" layout="row" layout-align="start start" class="wz-margin-left-10">

<select class="input input-dropdown" flex id="levelBox" ng-disabled="realtime" ng-model="type_log" placeholder="Log level"
class="md-no-underline" ng-change="filter({name:'type_log',value:type_log})" aria-label="Logs level">
<option value="all">All log levels</option>
<option value="info">Info</option>
<option value="error">Error</option>
<option value="warning">Warning</option>
<option value="critical">Critical</option>
<option value="debug">Debug</option>
</select>

<select flex ng-show='nodeList && nodeList.length' class="input input-dropdown wz-margin-left-10" id="categoryBox"
ng-model="selectedNode" ng-change="changeNode(selectedNode)" aria-label="Logs category">
<option ng-repeat="node in nodeList" value="{{node}}">{{node}}</option>
</select>

<select class="input input-dropdown wz-margin-left-10" flex id="categoryBox" ng-disabled="realtime" ng-model="category"
ng-change="filter({name:'category',value:category})" aria-label="Logs category">
<option value="all">All daemons</option>
<option ng-repeat="daemon in daemons | orderObjectBy: 'title'" value="{{daemon.title}}">{{daemon.title}}</option>
</select>

<!-- Switch to sort by timestamp -->
<md-switch class="wz-switch wz-padding-left-15" aria-label="Descending sort" ng-model="sortFilter" ng-change="sort()">
<div class="md-label">Descending sort</div>
</md-switch>

<!-- White space between filters and Realtime button -->
<span flex></span>

<md-button ng-if="!realtime" class="wz-button md-raised md-primary wz-margin-right-15" style='margin-top:-4px;'
ng-click="playRealtime()" aria-label="Play realtime button">
<i class="fa fa-play fa-fw" aria-hidden="true"></i>
Play realtime
</md-button>
<md-button ng-if="realtime" class="wz-button md-raised md-primary wz-margin-right-15" style='margin-top:-4px;'
ng-click="stopRealtime()" aria-label="Stop realtime button">
<i class="fa fa-stop fa-fw" aria-hidden="true"></i>
Stop realtime
</md-button>
</div>

<div layout="row">

<input flex placeholder="Filter logs..." ng-model="custom_search" type="text" class="kuiLocalSearchInput ng-empty ng-pristine ng-scope ng-touched ng-valid wz-margin-top-4 height-36 wz-margin-left-10"
aria-invalid="false" wz-enter="search(custom_search)">
<button type="submit" aria-label="Search" class="kuiLocalSearchButton height-36 wz-margin-top-4 wz-margin-right-16"
ng-click="search(custom_search)">
<span class="fa fa-search" aria-hidden="true"></span>
</button>
</div>
<!-- End Filters and Realtime button section -->

<!-- Logs section -->
<div layout="row" layout-padding ng-if="logsPath" ng-hide="true">
<wazuh-table flex extra-limit="100" path="logsPath" implicit-sort="'timestamp'" keys="['timestamp',{value:'tag',size:2},'level',{value:'description',size:4,nosortable:true}]"
rows-per-page="15">
</wazuh-table>
</div>
<div layout="row" layout-padding ng-show="XMLContent">
<wz-config-viewer flex xmlcontent="XMLContent" hide-header="true" />
</div>
<!-- End Logs section -->

<div layout="row" class="wz-margin-top-10">
<div layout="row" class="wz-margin-top-10 wz-margin-right-20">
<span flex></span>
<a class="small" id="btnDownload" ng-click="downloadCsv()">Formatted
<i aria-hidden="true" class="fa fa-fw fa-download"></i>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
define(['../../module', 'FileSaver'], function(app) {
define(['../../module', 'FileSaver'], function (app) {
'use strict'

class Logs {
Expand Down Expand Up @@ -26,11 +26,16 @@ define(['../../module', 'FileSaver'], function(app) {
this.notification = $notificationService
this.scope.type_log = 'all'
this.scope.category = 'all'
this.scope.sortFilter = false
this.api = $currentDataService.getApi()
this.logs = logs
this.csvReq = $csvRequestService
this.wzTableFilter = $tableFilterService
this.path = '/manager/logs'
this.scope.$on('scrolledToBottom', (ev, parameters) => {
if (!this.scope.realtime)
this.scope.$broadcast('increaseLogs', { lines: parameters.lines })
})
}

/**
Expand All @@ -46,11 +51,44 @@ define(['../../module', 'FileSaver'], function(app) {
this.scope.summary = this.logs.data.data
this.scope.downloadCsv = () => this.downloadCsv()
this.initialize()

this.scope.sort = () => this.sort()
this.scope.$on('wazuhFetched', (ev, params) => {
this.scope.XMLContent = this.parseLogsToText(params.items)
this.scope.$broadcast('XMLContentReady', { data: this.scope.XMLContent })
this.scope.$applyAsync()
})

} catch (err) {
this.notification.showErrorToast('Cannot fetch logs data from server')
}
}

/**
* Parse json logs to plane text
* @param {Object} logs
*/
parseLogsToText(logs) {
try {
let result = ''
logs.map(log => {
if (log) {
result += `${log.timestamp} ${log.tag} ${(log.level || '').toUpperCase()}: ${log.description}\n`
}
})
return result
} catch (error) {
this.notification.showErrorToast('Cannot parse logs.')
}
}

/**
* Sorts logs by timestamp
*/
sort() {
this.scope.$broadcast('wazuhSort', { field: 'timestamp' })
}

/**
* Exports the table in CSV format
*/
Expand Down Expand Up @@ -114,8 +152,8 @@ define(['../../module', 'FileSaver'], function(app) {

const data = this.clusterEnabled
? await this.apiReq(
`/cluster/${this.scope.selectedNode}/logs/summary`
)
`/cluster/${this.scope.selectedNode}/logs/summary`
)
: await this.apiReq('/manager/logs/summary')
const daemons = data.data.data
this.scope.daemons = Object.keys(daemons).map(item => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<div layout="row" ng-show="jsoncontent || xmlcontent" style="height: calc(100vh - 240px);">
<div layout="row" ng-show="jsoncontent || xmlcontent" ng-style="hideHeader && {'height': 'calc(100vh - 375px)'} || {'height': 'calc(100vh - 240px)'}">

<!-- JSON card -->
<md-card flex="auto" class="wz-md-card" ng-show="jsoncontent">
<md-card-content flex layout="column">
<div layout="row" layout-align="start center">
<md-card flex="auto" class="wz-md-card" ng-show="jsoncontent" ng-class="{'wz-no-margin':hideHeader}">
<md-card-content flex layout="column" ng-class="{'wz-no-padding':hideHeader}">
<div layout="row" layout-align="start center" ng-hide="hideHeader">
<div>
<span class="font-size-16">JSON viewer</span>
<div class="wz-margin-top-10">
Expand All @@ -15,7 +15,7 @@
<span class="small">&nbsp;&centerdot;&nbsp;</span>
<span ng-class="xmlcontent ? 'wz-text-active' : ''" class="wz-text-link small" ng-click="callgetxml()">XML</span>
</div>
<md-divider class="wz-margin-top-10"></md-divider>
<md-divider class="wz-margin-top-10" ng-hide="hideHeader"></md-divider>

<!-- The JSON viewer -->
<div class='wzJsonXmlEditorBody'>
Expand All @@ -27,9 +27,9 @@
<!-- End JSON card -->

<!-- XML card -->
<md-card flex="auto" class="wz-md-card" ng-show="xmlcontent">
<md-card-content flex layout="column">
<div layout="row" layout-align="start center">
<md-card flex="auto" class="wz-md-card" ng-show="xmlcontent" ng-class="{'wz-no-margin':hideHeader}">
<md-card-content flex layout="column" ng-class="{'wz-no-padding':hideHeader}">
<div layout="row" layout-align="start center" ng-hide="hideHeader">
<div>
<span class="font-size-16">XML viewer</span>
<div class="wz-margin-top-10">
Expand All @@ -41,7 +41,7 @@
<span class="small">&nbsp;&centerdot;&nbsp;</span>
<span ng-class="xmlcontent ? 'wz-text-active' : ''" class="wz-text-link small" ng-click="callgetxml()">XML</span>
</div>
<md-divider class="wz-margin-top-10"></md-divider>
<md-divider class="wz-margin-top-10" ng-hide="hideHeader"></md-divider>

<!-- The XML viewer -->
<div class='wzJsonXmlEditorBody'>
Expand Down
Loading

0 comments on commit c263392

Please sign in to comment.