Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log viewer and fix when downloading csv file #604

Merged
merged 12 commits into from
Mar 12, 2019
Merged
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