-
Notifications
You must be signed in to change notification settings - Fork 0
Logs
The Plotly Plugin for Grafana allows the user to make dynamic graphs. In this page we will explore how to make the table graph to display the logs.
http://10.8.8.148/eds/logs?telescope=clay&start_ts=${__from:date:YYYY-MM-DDTHH}:${__from:date:mm}:${__from:date:ss}&severity=${Severity}&text=${keyword}
- End-Point: From where the data is received
- Telescope: Either 'baade' or 'clay', no capital letters
- Date Format: We retrieve the starting date from the 'from' global variable, we call each variable with the ${variable_name} syntaxis, since this is a global variable we name it with '__', we also want a specific date format, that includes the ':' symbol. This is not supported by the grafana variable, so we divide the calling, getting the ':' symbol outside.
- Custom variables: These are declared in the panel settings, they must be named and called with the same syntaxis, these variables are named 'Severity' (with a capital 'S') and 'keyword' (no capital letters), but the label in the panel is different.
if(data.series[0].fields.length > 1){
severity = data.series[0].fields[2].values;
code = data.series[0].fields[0].values;
message = data.series[0].fields[1].values;
subsystem = data.series[0].fields[3].values;
ts = data.series[0].fields[4].values;
}
else{
severity = ['No Data']
code = ['No Data'];
message = ['No Data'];
subsystem = ['No Data'];
ts = ['No Data'];
}
We obtain the data that grafana (that our queries provide), for example on the line
severity = data.series[0].fields[2].values;
the list named data (a reserved value) stores all the data obtained by the data selector (our queries), then the sub-list series stores all the queries available on the data source, the sub-sub-list fields stores all the fields available on said query, finally the values stores a list with all the available values from the query.
As we are working with multiple filters, there is a chance that NO data is retrieved, in that case we do not want our visualization to crash, so at the beginning of the code we decide whether there is data on our query, or if it only contains one field (the one that states the null value).
allSubsystems = subsystem.filter(function (v, i, self) {
return i == self.indexOf(v);
});
timeStamp = ts.map(function (value, index){
timeFormatted = (new Date(value)).toUTCString()
return timeFormatted
});
Firstly we obtain all unique data from the subsystems for later filtering. Then we sanitize the time stamp, by returning a string value that is readable.
In order to filter, we first need something to filter and update, that is why we store a table with no filtered values. Since we want a table, we format the values as a multi-dimensional List, that we later add to the table.
var valuesAll = [code,
message,
severity,
subsystem,
timeStamp
];
var tableAll = {
type: 'table',
visible: 'true',
header: {
values: [["<b>Code</b>"], ["<b>Message</b>"],
["<b>Severity</b>"], ["<b>Subsystem</b>"], ["<b>ts</b>"]],
align: "center",
line: {width: 1, color: 'black'},
fill: {color: "grey"},
font: {family: "Arial", size: 12, color: "white"}
},
cells: {
values: valuesAll,
align: "center",
fill: {
color: [getColor(severity)]
},
line: {color: "black", width: 1},
font: {family: "Arial", size: 11, color: ["black"]}
},
}
In order to get the colors right for each row, we run the following function:
function getColor(arr)
{ var colors = arr.map(function(val, index){
var color = '';
switch(val){
case 'info':
color = 'skyblue';
break;
case 'warning':
color = 'orange';
break;
case 'error':
color = 'red';
break;
default:
color = 'white';
break;
}
return color
})
return colors
}
where the data required (arr), must be the severity column.
function getSpecificSubsystem(arr, subsystemV){
vals = arr.map(function (val, index){
if(subsystem[index].includes(subsystemV)){
return val
}
});
return vals.filter(function( element ) {
return element !== undefined;
});
}
We use the previous function to determine which rows of the complete data belong to a given subsystem.
In order to update the table we must first choose which part of the table declaration we need to update, in this case is cells, to avoid complications, we will update the entire cells dictionary. Then we apply the given subsystem(stored in subsystemV), and store all the columns on a list, to then input it on the values attribute. Finally we update the colors.
function generateData(subsystemV){
codeS = getSpecificSubsystem(code, subsystemV)
messageS = getSpecificSubsystem(message, subsystemV)
severityS = getSpecificSubsystem(severity, subsystemV)
subsystemS = getSpecificSubsystem(subsystem, subsystemV)
timeStampS = getSpecificSubsystem(timeStamp, subsystemV)
valuesS = [codeS, messageS, severityS, subsystemS, timeStampS]
cells = {
values: valuesS,
align: "center",
fill: {
color: [getColor(severityS)]
},
line: {color: "black", width: 1},
font: {family: "Arial", size: 11, color: ["black"]}
}
customdata = selected_severity
return [cells,customdata]
}
On the Plotly framework, we must declare what each button does, and how it affects the main table. So we use the following function, that returns a list of formatted buttons, that were populated according to a given array.
function getButtons(arr){
var buttons = []
for(var i = 0; i < arr.length; i++){
button = {
method: 'update',
args: [{'cells': generateData(arr[i])}],
label: arr[i]
}
buttons.push(button)
}
return buttons
}
To finish the filtering process we declare the variable updatemenus, that contains the button set, and we add it to the layout variable.
updatemenus = [ {
yanchor: 'bottom',
buttons: getButtons(allSubsystems)
},
]
layoutTable = {
updatemenus : updatemenus,
}
var data = [tableAll];
return{data: data, layout: layoutTable}
We add the rendered table to the data variable, to finally return it into the required by the plugin dictionary, along with the layout.