alpha state
This commit is contained in:
parent
0829e920bc
commit
a5ee6111fc
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
|||||||
job-visualizer
|
job-visualizer
|
||||||
|
/*.csv
|
||||||
|
/*.html
|
||||||
|
33
README.md
Normal file
33
README.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Job Visualizer
|
||||||
|
This project is meant to visualize scheduled jobs for a given timespan,
|
||||||
|
so you're able to see bottlenecks or timeframes where to many jobs are run simultaneously.
|
||||||
|
|
||||||
|
**This tool analyzes a CSV file and creates an HTML file.**
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
For usage information call
|
||||||
|
```
|
||||||
|
./job-visualizer -h
|
||||||
|
```
|
||||||
|
|
||||||
|
That will result in
|
||||||
|
```
|
||||||
|
Usage of ./job-visualizer:
|
||||||
|
-file string
|
||||||
|
File to import
|
||||||
|
-output string
|
||||||
|
File to generate
|
||||||
|
```
|
||||||
|
|
||||||
|
* `--file` Is a csv file you want to analyze
|
||||||
|
* `--output` Is an html file the tool will generate
|
||||||
|
|
||||||
|
### CSV File Format
|
||||||
|
Currently the format is fixed and planned to be configurable in the future.
|
||||||
|
|
||||||
|
You need the following columns:
|
||||||
|
* Prefix/Group
|
||||||
|
* job_name: The name of the job
|
||||||
|
* job_type: The type of the job
|
||||||
|
* start_time: A string with start times for the group, e.g. `"2019-11-02 21:10:21,2019-11-03 21:19:33"`
|
||||||
|
* end_time: As start_time, but the end times, e.g. `"2019-11-02 21:10:22,2019-11-03 21:19:33"`
|
60
main.go
60
main.go
@ -7,33 +7,39 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var file = flag.String("file", "", "File to import")
|
var file = flag.String("file", "", "File to import")
|
||||||
var columnStart = flag.Int("columnStart", -1, "Column number with a start Datetime")
|
var output = flag.String("output", "", "File to generate")
|
||||||
var columnEnd = flag.Int("columnEnd", -1, "Column number with a end Datetime")
|
//var columnStart = flag.Int("columnStart", -1, "Column number with a start Datetime")
|
||||||
var columnDescription = flag.Int("columnDescription", -1, "Column number with a descriptive name or similar")
|
//var columnEnd = flag.Int("columnEnd", -1, "Column number with a end Datetime")
|
||||||
|
//var columnDescription = flag.Int("columnDescription", -1, "Column number with a descriptive name or similar")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if _, err := os.Stat(*file); os.IsNotExist(err) || *columnStart == -1 || *columnEnd == -1 || *columnDescription == -1 {
|
if _, err := os.Stat(*file); os.IsNotExist(err) || *output == "" {
|
||||||
flag.Usage()
|
flag.Usage()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Scanning file " + *file + "...")
|
fmt.Println("Analyzing " + *file + "...")
|
||||||
readCsvFile(*file, *columnStart, *columnEnd, *columnDescription)
|
readCsvFile(*file, *output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readCsvFile(csvFile string, columnStart int, columnEnd int, columnDescription int) {
|
func readCsvFile(input string, output string) {
|
||||||
f, _ := os.Open(csvFile)
|
csvFile, _ := os.Open(input)
|
||||||
r := csv.NewReader(bufio.NewReader(f))
|
reader := csv.NewReader(bufio.NewReader(csvFile))
|
||||||
|
|
||||||
type JobDetails struct {
|
type JobDetails struct {
|
||||||
Start string
|
Id int
|
||||||
End string
|
Name string
|
||||||
Description string
|
Type string
|
||||||
|
Provider string
|
||||||
|
Start []string
|
||||||
|
End []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ViewData struct {
|
type ViewData struct {
|
||||||
@ -42,25 +48,43 @@ func readCsvFile(csvFile string, columnStart int, columnEnd int, columnDescripti
|
|||||||
|
|
||||||
var data ViewData
|
var data ViewData
|
||||||
|
|
||||||
|
id := 0
|
||||||
for {
|
for {
|
||||||
row, err := r.Read()
|
row, err := reader.Read()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id++
|
||||||
job := JobDetails{
|
job := JobDetails{
|
||||||
Start: row[columnStart],
|
Id: id,
|
||||||
End: row[columnEnd],
|
Name: row[1],
|
||||||
Description: row[columnDescription],
|
Type: row[2],
|
||||||
|
Provider: row[0],
|
||||||
|
Start: strings.Split(row[3], ","),
|
||||||
|
End: strings.Split(row[4], ","),
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Jobs = append(data.Jobs, job)
|
data.Jobs = append(data.Jobs, job)
|
||||||
}
|
}
|
||||||
|
fmt.Println("Scanning done.")
|
||||||
|
|
||||||
|
fmt.Println("Creating template...")
|
||||||
tpl, err := template.ParseFiles("template.html")
|
tpl, err := template.ParseFiles("template.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
fmt.Printf("%+v\n", data)
|
|
||||||
tpl.Execute(os.Stdout, data)
|
outputFile, err := os.Create(output)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("create file: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = tpl.Execute(outputFile, data)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("execute: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
outputFile.Close()
|
||||||
|
fmt.Println("Generated " + output)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,65 @@
|
|||||||
<html>
|
<html>
|
||||||
<table>
|
<head>
|
||||||
{{ range .Jobs }}
|
<link href="https://cdn.dhtmlx.com/gantt/edge/dhtmlxgantt.css" rel="stylesheet"/>
|
||||||
<tr>
|
<script src="https://cdn.dhtmlx.com/gantt/edge/dhtmlxgantt.js"></script>
|
||||||
<td>{{ .Description }}</td>
|
<script src="https://cdn.dhtmlx.com/gantt/edge/ext/dhtmlxgantt_tooltip.js"></script>
|
||||||
</tr>
|
<script src="https://cdn.dhtmlx.com/gantt/edge/ext/dhtmlxgantt_keyboard_navigation.js"></script>
|
||||||
{{ end }}
|
<script src="https://cdn.dhtmlx.com/gantt/edge/ext/dhtmlxgantt_multiselect.js"></script>
|
||||||
</table>
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="gantt_here" style="width:100%; height:100%"></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
gantt.config.date_format = "%Y-%m-%d %H:%i:%s";
|
||||||
|
gantt.config.scales = [
|
||||||
|
{unit: "day", step: 1, format: "%Y-%m-%d"},
|
||||||
|
{unit: "hour", step: 1, format: "%H"},
|
||||||
|
];
|
||||||
|
gantt.config.readonly = true;
|
||||||
|
gantt.config.auto_types = true;
|
||||||
|
gantt.config.auto_scheduling = true;
|
||||||
|
gantt.config.auto_scheduling_compatibility = true;
|
||||||
|
gantt.config.columns = [
|
||||||
|
{name:"text", label:"Task name", width:"400", tree:true }
|
||||||
|
];
|
||||||
|
gantt.config.layout = {
|
||||||
|
css: "gantt_container",
|
||||||
|
cols:[
|
||||||
|
{
|
||||||
|
width:400,
|
||||||
|
min_width: 300,
|
||||||
|
rows:[
|
||||||
|
{view: "grid", scrollX: "gridScroll", scrollable: true, scrollY: "scrollVer"},
|
||||||
|
{view: "scrollbar", id: "gridScroll", group:"horizontal"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{resizer: true, width: 1},
|
||||||
|
{
|
||||||
|
rows:[
|
||||||
|
{view: "timeline", scrollX: "scrollHor", scrollY: "scrollVer"},
|
||||||
|
{view: "scrollbar", id: "scrollHor", group:"horizontal"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{view: "scrollbar", id: "scrollVer"}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
gantt.config.show_errors = false;
|
||||||
|
gantt.init("gantt_here");
|
||||||
|
|
||||||
|
jobs = {
|
||||||
|
"data": [
|
||||||
|
{{ range $index, $job := .Jobs }}
|
||||||
|
{"id": {{ $job.Id }}, "text": "{{ $job.Provider }} - {{ $job.Type }} - {{ $job.Name }}", "start_date": "{{ index $job.Start 0 }}", "open": false, "render":"split"},
|
||||||
|
{{ range $startIndex, $start := $job.Start }}
|
||||||
|
{{ $end := index $job.End $startIndex }}
|
||||||
|
{"text": "{{ $job.Type }}: {{ $job.Name }}", "start_date": "{{ $start }}", "end_date": "{{ $end }}", "parent": {{ $job.Id }}, "open": true},
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
],
|
||||||
|
"links": []
|
||||||
|
};
|
||||||
|
|
||||||
|
gantt.parse(jobs);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
3
test.csv
3
test.csv
@ -1,3 +0,0 @@
|
|||||||
2019-01-01 00:00:00,2019-01-01 00:08:00,echo Hello
|
|
||||||
2019-01-03 01:05:00,2019-01-03 03:14:00,echo Ola
|
|
||||||
2019-01-03 01:07:00,2019-01-03 12:45:00,echo Aloah
|
|
|
Loading…
Reference in New Issue
Block a user