Skip to content

Commit

Permalink
Added custom tables and HTML reports on the Job Details page.
Browse files Browse the repository at this point in the history
Bumped version to 0.2.0.
  • Loading branch information
jhuckaby committed Apr 3, 2016
1 parent d5ff383 commit 4fef7db
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 2 deletions.
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1475,6 +1475,71 @@ You can pass custom JSON data to the next event in the chain, when using a [Chai

So in this case when the event `e29bf12db` runs, it will be passed your `chain_data` object as part of the JSON sent to it when the job starts. The Plugin code running the chained event can access the data by parsing the JSON and grabbing the `chain_data` property.

#### Custom Data Tables

If your Plugin produces statistics or other tabular data at the end of a run, you can have Cronicle render this into a table on the Job Details page. Simply print a JSON object with a property named `table`, containing the following keys:

| Property Name | Description |
|---------------|-------------|
| `title` | Optional title displayed above the table, defaults to "Job Stats". |
| `header` | Optional array of header columns, displayed in shaded bold above the main data rows. |
| `rows` | **Required** array of rows, with each one being its own inner array of column values. |
| `caption` | Optional caption to show under the table (centered, small gray text). |

Here is an example data table. Note that this has been expanded for documentation purposes, but in practice your JSON needs to be compacted onto a single line when printed to STDOUT.

```js
{
"table": {
"title": "Sample Job Stats",
"header": [
"IP Address", "DNS Lookup", "Flag", "Count", "Percentage"
],
"rows": [
["62.121.210.2", "directing.com", "MaxEvents-ImpsUserHour-DMZ", 138, "0.0032%" ],
["97.247.105.50", "hsd2.nm.comcast.net", "MaxEvents-ImpsUserHour-ILUA", 84, "0.0019%" ],
["21.153.110.51", "grandnetworks.net", "InvalidIP-Basic", 20, "0.00046%" ],
["95.224.240.69", "hsd6.mi.comcast.net", "MaxEvents-ImpsUserHour-NM", 19, "0.00044%" ],
["72.129.60.245", "hsd6.nm.comcast.net", "InvalidCat-Domestic", 17, "0.00039%" ],
["21.239.78.116", "cable.mindsprung.com", "InvalidDog-Exotic", 15, "0.00037%" ],
["172.24.147.27", "cliento.mchsi.com", "MaxEvents-ClicksPer", 14, "0.00035%" ],
["60.203.211.33", "rgv.res.com", "InvalidFrog-Croak", 14, "0.00030%" ],
["24.8.8.129", "dsl.att.com", "Pizza-Hawaiian", 12, "0.00025%" ],
["255.255.1.1", "favoriteisp.com", "Random-Data", 10, "0%" ]
],
"caption": "This is an example stats table you can generate from within your Plugin code."
}
}
```

This would produce a table like the following:

![Custom Stats Table Example](https://pixlcore.com/software/cronicle/screenshots/job-details-custom-table.png)

#### Custom HTML Content

If you would prefer to generate your own HTML content from your Plugin code, and just have it rendered into the Job Details page, you can do that as well. Simply print a JSON object with a property named `html`, containing the following keys:

| Property Name | Description |
|---------------|-------------|
| `title` | Optional title displayed above the section, defaults to "Job Report". |
| `content` | **Required** Raw HTML content to render into the page. |
| `caption` | Optional caption to show under your HTML (centered, small gray text). |

Here is an example HTML report. Note that this has been expanded for documentation purposes, but in practice your JSON needs to be compacted onto a single line when printed to STDOUT.

```js
{
"html": {
title: "Sample Job Report",
content: "This is <b>HTML</b> so you can use <i>styling</i> and such.",
caption: "This is a caption displayed under your HTML content."
}
}
```

If your Plugin generates plain text instead of HTML, you can just wrap it in a `<pre>` block, which will preserve formatting such as whitespace.

### Environment Variables

When processes are spawned to run jobs, your Plugin executable is provided with a copy of the current environment, along with all the following custom variables:
Expand Down
32 changes: 31 additions & 1 deletion bin/test-plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,44 @@ stream.on('json', function(job) {
perf.perf.gzip_data = { end: 1, elapsed: rand_range(max * 0.6, max * 0.9) };
perf.perf.http_post = { end: 1, elapsed: rand_range(max * 0.8, max * 1) };

// include a table with some stats
var table = {
title: "Sample Job Stats",
header: [
"IP Address", "DNS Lookup", "Flag", "Count", "Percentage"
],
rows: [
["62.121.210.2", "directing.com", "MaxEvents-ImpsUserHour-DMZ", 138, "0.0032%" ],
["97.247.105.50", "hsd2.nm.comcast.net", "MaxEvents-ImpsUserHour-ILUA", 84, "0.0019%" ],
["21.153.110.51", "grandnetworks.net", "InvalidIP-Basic", 20, "0.00046%" ],
["95.224.240.69", "hsd6.mi.comcast.net", "MaxEvents-ImpsUserHour-NM", 19, "0.00044%" ],
["72.129.60.245", "hsd6.nm.comcast.net", "InvalidCat-Domestic", 17, "0.00039%" ],
["21.239.78.116", "cable.mindsprung.com", "InvalidDog-Exotic", 15, "0.00037%" ],
["172.24.147.27", "cliento.mchsi.com", "MaxEvents-ClicksPer", 14, "0.00035%" ],
["60.203.211.33", "rgv.res.com", "InvalidFrog-Croak", 14, "0.00030%" ],
["24.8.8.129", "dsl.att.com", "Pizza-Hawaiian", 12, "0.00025%" ],
["255.255.1.1", "favoriteisp.com", "Random-Data", 10, "0%" ]
],
caption: "This is an example stats table you can generate from within your Plugin code."
};

// include a custom html report
var html = {
title: "Sample Job Report",
content: "<pre>This is a sample text report you can generate from within your Plugin code (can be HTML too).\n\n-------------------------------------------------\n Date/Time | 2015-10-01 6:28:38 AM \n Elapsed Time | 1 hour 15 minutes \n Total Log Rows | 4,313,619 \n Skipped Rows | 15 \n Pre-Filtered Rows | 16,847 \n Events | 4,296,757 \n Impressions | 4,287,421 \n Backup Impressions | 4,000 \n Clicks | 5,309 (0.12%) \n Backup Clicks | 27 (0.00062%) \n Unique Users | 1,239,502 \n Flagged Users | 1,651 \n Ignored Users | 1,025,910 \n Other Users | 211,941 \n Flagged Events | 6,575 (0.15%) \nFlagged Impressions | 6,327 (0.14%) \n Flagged Clicks | 241 (4.53%) \n Memory Usage | 7.38 GB \n-------------------------------------------------</pre>",
caption: ""
};

switch (job.params.action) {
case 'Success':
logger.debug(9, "Simulating a successful response");
stream.write({
complete: 1,
code: 0,
description: "Success!",
perf: perf.summarize()
perf: perf.summarize(),
table: table,
html: html
});
break;

Expand Down
52 changes: 52 additions & 0 deletions htdocs/js/pages/JobDetails.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,58 @@ Class.subclass( Page.Base, "Page.JobDetails", {

html += '</div>';

// custom data table
if (job.table && job.table.rows && job.table.rows.length) {
var table = job.table;
html += '<div class="subtitle" style="margin-top:15px;">' + (table.title || 'Job Stats') + '</div>';
html += '<table class="data_table" style="width:100%">';

if (table.header && table.header.length) {
html += '<tr>';
for (var idx = 0, len = table.header.length; idx < len; idx++) {
html += '<th>' + table.header[idx] + '</th>';
}
html += '</tr>';
}

var filters = table.filters || [];

for (var idx = 0, len = table.rows.length; idx < len; idx++) {
var row = table.rows[idx];
if (row && row.length) {
html += '<tr>';

for (var idy = 0, ley = row.length; idy < ley; idy++) {
var col = row[idy];
html += '<td>';
if (typeof(col) != 'undefined') {
if (filters[idy] && window[filters[idy]]) html += window[filters[idy]](col);
else if ((typeof(col) == 'string') && col.match(/^filter\:(\w+)\((.+)\)$/)) {
var filter = RegExp.$1;
var value = RegExp.$2;
if (window[filter]) html += window[filter](value);
else html += value;
}
else html += col;
}
html += '</td>';
} // foreach col

html += '</tr>';
} // good row
} // foreach row

html += '</table>';
if (table.caption) html += '<div class="caption" style="margin-top:4px; text-align:center;">' + table.caption + '</div>';
} // custom data table

// custom html table
if (job.html) {
html += '<div class="subtitle" style="margin-top:15px;">' + (job.html.title || 'Job Report') + '</div>';
html += '<div>' + job.html.content + '</div>';
if (job.html.caption) html += '<div class="caption" style="margin-top:4px; text-align:center;">' + job.html.caption + '</div>';
}

// job log (IFRAME)
html += '<div class="subtitle" style="margin-top:15px;">';
html += 'Job Event Log';
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Cronicle",
"version": "0.1.9",
"version": "0.2.0",
"description": "A simple, distributed task scheduler and runner with a web based UI.",
"author": "Joseph Huckaby <[email protected]>",
"homepage": "https://github.com/jhuckaby/Cronicle",
Expand Down

0 comments on commit 4fef7db

Please sign in to comment.