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

feat(sumologic-image-widget) : Hubot can display widget from a sumologic dashboard #8

Open
wants to merge 40 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
980a8c4
Some test to get dashboard widget data
Mar 9, 2016
2061918
Start implement dashboard show cmd
Mar 11, 2016
e730a35
feat(package) : Set package info and dev task
julien-vidal Mar 20, 2016
fcff3f7
feat(sumologic-image-widget) : Test gist, shit and doc it
julien-vidal Mar 20, 2016
6fc5fec
feat(sumologic-image-widget) : Play with sumologic data and revertengine
julien-vidal Mar 20, 2016
83586d2
feat(sumologic-image-widget) : Push some refactor on dashboard...
Mar 21, 2016
e1e6ade
feat(sumologic-image-widget) : Start implementing show widget
julien-vidal Mar 23, 2016
d9f587c
Merge branch 'payou-playground-graph-img-generation' of https://githu…
Mar 23, 2016
d8d0e64
feat(sumologic-image-widget) : Start stackedBarFormatter
Mar 23, 2016
7df37a3
feat(sumologic-image-widget) : First working version
Mar 24, 2016
f9c01c9
feat(sumologic-image-widget) : Hubot listen for sumo command
julien-vidal Mar 24, 2016
b2fce86
feat(sumologic-image-widget) : Add Pie formatter
julien-vidal Mar 25, 2016
e5d0be9
feat(sumologic-image-widget) : Add some others chart to implement
julien-vidal Mar 25, 2016
02a531f
feat(sumologic-image-widget) : Add missing mocks for front dashboard
Mar 25, 2016
a538572
feat(sumologic-image-widget) : remove sumo token from code
julien-vidal Mar 26, 2016
3e0101e
feat(sumologic-image-widget) : Refactor chain architecture
julien-vidal Mar 26, 2016
1f1c0d9
feat(sumologic-image-widget) : Refactor fixing
julien-vidal Mar 26, 2016
ce65ee8
feat(sumologic-image-widget) : add linesChart support
julien-vidal Mar 27, 2016
ecb60fe
feat(sumologic-image-widget) : add (time)counter charts
julien-vidal Mar 27, 2016
07b7942
feat(sumologic-image-widget) : Refactor how graphBuilder getGraph
julien-vidal Mar 27, 2016
635a6db
feat(sumologic-image-widget) : Start implementing (time)counter
julien-vidal Mar 27, 2016
b926583
feat(sumologic-image-widget) : (time)counter Done
julien-vidal Mar 28, 2016
1d7292b
feat(sumologic-image-widget) : Update roadmap
julien-vidal Mar 28, 2016
1a167f5
feat(sumologic-image-widget) : Fix how counter transform data
julien-vidal Mar 28, 2016
11943d4
feat(sumologic-image-widget) : Add clean way to store graph file
Mar 29, 2016
b332496
feat(sumologic-image-widget) : Implement tmp folder and clean
julien-vidal Mar 29, 2016
14cdf05
feat(sumologic-image-widget) : Start refactor of file management
Mar 30, 2016
354316c
feat(sumologic-image-widget) : Implement fileHelper
Apr 7, 2016
b23a562
feat(sumologic-image-widget) : End FileHelper integration
Apr 8, 2016
774006f
feat(sumologic-image-widget) : Add Highcharts theme support
Apr 8, 2016
a765019
feat(sumologic-image-widget) : Implement how to learn to hubot
julien-vidal Apr 19, 2016
471223a
feat(sumologic-image-widget) : Comment dark theme
julien-vidal Apr 19, 2016
7a12d13
feat(sumologic-image-widget) : Tidy file by purposes
Apr 21, 2016
954f54e
feat(sumologic-image-widget) : Remap dependencies due to previous tidy
Apr 21, 2016
8998270
feat(sumologic-image-widget) : Add info message when hubot learn new …
Apr 21, 2016
c97938b
feat(sumologic-image-widget) : Rename method for erase sumo memory
Apr 21, 2016
3f8fced
feat(sumologic-image-widget) : Clean fileHelper
Apr 21, 2016
55fe6e9
feat(sumologic-image-widget) : Clean todo and clean
Apr 22, 2016
deae5f7
feat(sumologic-image-widget) : Add notification on hubot learnings
julien-vidal Apr 24, 2016
6a3159e
feat(sumologic-image-widget) : End error message on hubot learning fail
Apr 25, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules
.DS_Store*
.hubot_history
.idea
dump.rdb
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,67 @@ Add the subdomain hubot should connect to. If you web URL looks like

You may want to get comfortable with `heroku logs` and `heroku restart` if
you're having issues.


# (Payou - Experiments) Display a widget from sumologic

## Idea

From a Sumologic dashboard widget, be able to display it as an image

## How

Step one : Target the good widget
For now we can't do it easily while the dashboard API from Sumologic is broken.
For now we should link manually id to widget :cry:

Step two : Transform widget data to graph

Thanks to jsdom and highcharts we can transform what sumologic return to a graph.
This process will be manual in a first time for testing purpose, then a bit
industrialize to display all widget possible. Sumologic seems to use highcharts
for rendering their widget, so this part shouldn't be hard...

Step three : Transform svg graph to image

For now we will use svg2png, it use phamtomjs in background for extract png from
svg. Not the nicer solution but the easiest for now. Other lib are only wrapper
of lower image libs. Maybe this latest solution is faster than the previous and
we should consider it on long term maybe. But this one is harder to implement and
depend on which OS the hubot will run.

Step Four : Host/Send the img to slack

At first sight, Hubot should send image generated.
Not the hardest part, seems slack api have what we need to do it !
We just need to implement that part and we should be done !

Could send it to a third part and just send link in a channel to.

## usefull commands

```
// Will launch the test bouzin !
coffee ./scripts/hubot-sumologic-image-widget/main.coffee

// Will launch the gist test bouzin !
node ./scripts/hubot-sumologic-image-widget/gist.js
```

## Now

- [x] Tests the all chain !
- [ ] Use real data from sumologic widget
- [ ] Implement some highchart adapters depending of widget
- [ ] Refactor a lot
- [ ] Clean generated image file
- [ ] Use promises correctly
- [ ] Add Hubot hear for this dev
- [ ] Test on a true slack
- [ ] Clean it !

## At dev end

- [ ] Remove dev npm scripts
- [ ] Remove tests files
- [ ] Consider to package it
16 changes: 14 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
"name": "hubot",
"name": "hubot-mill",
"version": "0.0.0",
"description": "A simple helpful robot for your Company",
"description": "Our cool dear hubot which help us to make good things at Boulangerie",
"scripts": {
"dev": "./bin/hubot",
"payou-dev": "coffee ./scripts/hubot-sumologic-image-widget/main.coffee"
},
"dependencies": {
"gitio2": "^3.1.0",
"hubot": "^2.18.0",
Expand All @@ -26,5 +30,13 @@
"engines": {
"node": "0.10.x",
"npm": "2.14.7"
},
"devDependencies": {
"form-data": "^0.2.0",
"highcharts": "^4.2.3",
"jsdom": "^8.1.0",
"moment": "^2.12.0",
"pn": "^1.0.0",
"svg2png": "^3.0.0"
}
}
38 changes: 37 additions & 1 deletion scripts/dashboard.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ class Dashboard
@robot.brain.data.dashboard.sumologic.dashboards = dashboards
done(@robot.brain.data.dashboard.sumologic.dashboards)

getSumologicDashboardData: (dashId) ->
@robot.http("https://api.sumologic.com/api/v1/dashboards/"+dashId+"/data")
.header('Authorization', 'Basic ' + Dashboard.SumologicToken)
.get() (err, res, body) =>
dashboardData = JSON.parse(body).dashboardMonitorDatas
console.log JSON.stringify(dashboardData, null, 4)

getSumologicDashboardInfo: (dashId) ->
@robot.http("https://api.sumologic.com/api/v1/dashboards/"+dashId)
.header('Authorization', 'Basic ' + Dashboard.SumologicToken)
.get() (err, res, body) =>
dashboardInfo = JSON.parse(body).dashboard
console.log JSON.stringify(dashboardInfo, null, 4)


Util = require "util"
_ = require "lodash"
Expand All @@ -49,6 +63,7 @@ module.exports = (robot) ->
Dashboard URL manager
`!dashboard set <url>` : Switch to given URL
`!dashboard sumo <dashboardId>` : Switch to the dashboardId URL
`!dashboard show <dashboardId>-<widgetId>` : Get picture of a widget

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my mind, dashboard means the TV Dashboard :)
Maybe use a sumologic cmd ? :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is just for testing, will disappear when finished ^^

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for sure, feel free it's a dashboard TV manager, I don't have TV

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should buy one 😜
Really under construction lol, I think I will move my dev in an other place at the end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure I should buy one.
Waiting our office keys 🍭

`!dashboard [-c|--current]` : Display current URL
`!dashboard [-l|--list]` : List sumologic dashboard
`!dashboard [-d|--default]` : Set default dashboard
Expand Down Expand Up @@ -82,6 +97,15 @@ module.exports = (robot) ->
else if key in ["set"]
msg.send(dashboard.setCurrentUrl(value))

else if key in ["info"]
dashboard.getSumologicDashboardInfo(value)

else if key in ["data"]
dashboard.getSumologicDashboardData(value)

else if key in ["show"]
new WidgetDisplay(value).show()

else if key in ["sumo"]
dashboard.setCurrentUrl(Dashboard.getSumoURLById(value))
msg.send('Current url is now ' + dashboard.getCurrentUrl())
Expand Down Expand Up @@ -117,4 +141,16 @@ module.exports = (robot) ->
res.json({
url: dashboard.getCurrentUrl(),
history: dashboard.getHistory()
})
})


class WidgetDisplay
constructor: (@widgetKey) ->
[@dashboardId, @widgetId] = @widgetKey.split('-')

show: () ->
console.log "This is the widget #{@widgetId} from dashboard #{@dashboardId}"

fetch: () ->
console.log "I will fetch something from sumo"

70 changes: 70 additions & 0 deletions scripts/hubot-sumologic-image-widget/api-v1-errors-widget.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"fields": [
{
"keyField": true,
"name": "_timeslice",
"fieldType": "long"
},
{
"keyField": false,
"name": "404",
"fieldType": "int"
},
{
"keyField": false,
"name": "403",
"fieldType": "int"
}
],
"id": 11116785,
"isRecentlyStarted": false,
"records": [
{
"map": {
"403": "1",
"404": "1",
"_timeslice": "1458510720000"
}
},
{
"map": {
"404": "4",
"_timeslice": "1458510840000"
}
},
{
"map": {
"404": "4",
"_timeslice": "1458510960000"
}
},
{
"map": {
"404": "8",
"_timeslice": "1458511020000"
}
},
{
"map": {
"403": "6",
"404": "5",
"_timeslice": "1458511260000"
}
},
{
"map": {
"403": "1",
"404": "6",
"_timeslice": "1458511320000"
}
}
],
"resolvedTimeRange": {
"startMillis": 1458510705000,
"endMillis": 1458511605000
},
"recentlyStarted": false,
"queryStartTime": 1450433036159,
"lastUpdated": 1458511601768,
"warnings": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
module.exports = function (ns, tagName) {
var elem = this.doc.createElement(tagName);

// Set private namespace to satisfy jsdom's getter
elem._namespaceURI = ns; // eslint-disable-line no-underscore-dangle
/**
* Pass Highcharts' test for SVG capabilities
* @returns {undefined}
*/
elem.createSVGRect = function () {};
/**
* jsdom doesn't compute layout (see https://github.com/tmpvar/jsdom/issues/135).
* This getBBox implementation provides just enough information to get Highcharts
* to render text boxes correctly, and is not intended to work like a general
* getBBox implementation. The height of the boxes are computed from the sum of
* tspans and their font sizes. The width is based on an average width for each glyph.
* It could easily be improved to take font-weight into account.
* For a more exact result we could to create a map over glyph widths for several
* fonts and sizes, but it may not be necessary for the purpose.
* @returns {Object} The bounding box
*/
elem.getBBox = function () {
var lineWidth = 0,
width = 0,
height = 0;

[].forEach.call(elem.children.length ? elem.children : [elem], function (child) {
var fontSize = child.style.fontSize || elem.style.fontSize,
lineHeight,
textLength;

// The font size and lineHeight is based on empirical values, copied from
// the SVGRenderer.fontMetrics function in Highcharts.
if (/px/.test(fontSize)) {
fontSize = parseInt(fontSize, 10);
} else {
fontSize = /em/.test(fontSize) ? parseFloat(fontSize) * 12 : 12;
}
lineHeight = fontSize < 24 ? fontSize + 3 : Math.round(fontSize * 1.2);
textLength = child.textContent.length * fontSize * 0.55;

// Tspans on the same line
if (child.getAttribute('dx') !== '0') {
height += lineHeight;
}

// New line
if (child.getAttribute('dy') !== null) {
lineWidth = 0;
}

lineWidth += textLength;
width = Math.max(width, lineWidth);

});

return {
x: 0,
y: 0,
width: width,
height: height
};
};
return elem;
};
Loading