Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d638526

Browse files
Merge pull request dataplat#3892 from marcingminski/ConvertTo-DbaTimeline
Convert to dba timeline
2 parents e5e583a + e611a82 commit d638526

File tree

4 files changed

+322
-2
lines changed

4 files changed

+322
-2
lines changed

‎functions/ConvertTo-DbaTimeline.ps1

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
function ConvertTo-DbaTimeline {
2+
<#
3+
.SYNOPSIS
4+
Converts InputObject to a html timeline using Google Chart
5+
6+
.DESCRIPTION
7+
This function accepts input as pipeline from the following psdbatools functions:
8+
Get-DbaAgentJobHistory
9+
Get-DbaBackupHistory
10+
(more to come...)
11+
And generates Bootstrap based, HTML file with Google Chart Timeline
12+
13+
.PARAMETER InputObject
14+
15+
Pipe input, must an output from the above functions.
16+
17+
.PARAMETER EnableException
18+
By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message.
19+
This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting.
20+
Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch.
21+
22+
.NOTES
23+
Tags: Chart
24+
Author: Marcin Gminski (@marcingminski)
25+
Dependency: ConvertTo-JsDate, Convert-DbaTimelineStatusColor
26+
27+
Website: https://dbatools.io
28+
Copyright: (C) Chrissy LeMaire, clemaire@gmail.com
29+
- License: MIT https://opensource.org/licenses/MIT
30+
31+
.LINK
32+
https://dbatools.io/ConvertTo-DbaTimeline
33+
34+
.EXAMPLE
35+
Get-DbaAgentJobHistory -SqlInstance sql-1 -StartDate '2018年08月13日 00:00' -EndDate '2018年08月13日 23:59' -NoJobSteps | ConvertTo-DbaTimeline | Out-File C:\temp\DbaAgentJobHistory.html -Encoding ASCII
36+
37+
Creates an output file containing a pretty timeline for all of the agent job history results for sql-1 the whole day of 2018年08月13日
38+
39+
.EXAMPLE
40+
Get-DbaRegisteredServer -SqlInstance sqlcm | Get-DbaBackupHistory -Since '2018年08月13日 00:00' | ConvertTo-DbaTimeline | Out-File C:\temp\DbaBackupHistory.html -Encoding ASCII
41+
42+
Creates an output file containing a pretty timeline for the agent job history since 2018年08月13日 for all of the registered servers on sqlcm
43+
44+
.EXAMPLE
45+
$messageParameters = @{
46+
Subject = "Backup history for sql2017 and sql2016"
47+
Body = Get-DbaBackupHistory -SqlInstance sql2017, sql2016 -Since '2018年08月13日 00:00' | ConvertTo-DbaTimeline
48+
From = "dba@ad.local"
49+
To = "dba@ad.local"
50+
SmtpServer = "smtp.ad.local"
51+
}
52+
Send-MailMessage @messageParameters -BodyAsHtml
53+
54+
Sends an email to dba@ad.local with the results of Get-DbaBackupHistory. Note that viewing these reports may not be supported in all email clients.
55+
#>
56+
57+
[CmdletBinding()]
58+
Param (
59+
[parameter(Mandatory, ValueFromPipeline)]
60+
[object[]]$InputObject,
61+
[switch]$EnableException
62+
)
63+
begin {
64+
$body = $servers = @()
65+
$begin = @"
66+
<html>
67+
<head>
68+
<!-- Developed by Marcin Gminski, https://marcin.gminski.net, 2018 -->
69+
<!-- Load jQuery required to autosize timeline -->
70+
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
71+
<!-- Load Bootstrap -->
72+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
73+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
74+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
75+
<!-- Load Google Charts library -->
76+
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
77+
<!-- a bit of custom styling to work with bootstrap grid -->
78+
<style>
79+
80+
html,body{height:100%;background-color:#c2c2c2;}
81+
.viewport {height:100%}
82+
83+
.chart{
84+
background-color:#fff;
85+
text-align:left;
86+
padding:0;
87+
border:1px solid #7D7D7D;
88+
-webkit-box-shadow:1px 1px 3px 0 rgba(0,0,0,.45);
89+
-moz-box-shadow:1px 1px 3px 0 rgba(0,0,0,.45);
90+
box-shadow:1px 1px 3px 0 rgba(0,0,0,.45)
91+
}
92+
.badge-custom{background-color:#939}
93+
.container {
94+
height:100%;
95+
}
96+
.fill{
97+
width:100%;
98+
height:100%;
99+
min-height:100%;
100+
padding:10px;
101+
}
102+
.timeline-tooltip{
103+
border:1px solid #E0E0E0;
104+
font-family:Arial,Helvetica;
105+
font-size:10pt;
106+
padding:12px
107+
}
108+
.timeline-tooltip div{padding:6px}
109+
.timeline-tooltip span{font-weight:700}
110+
</style>
111+
<script type="text/javascript">
112+
google.charts.load('43', {'packages':['timeline']});
113+
google.charts.setOnLoadCallback(drawChart);
114+
function drawChart() {
115+
var container = document.getElementById('Chart');
116+
var chart = new google.visualization.Timeline(container);
117+
var dataTable = new google.visualization.DataTable();
118+
dataTable.addColumn({type: 'string', id: 'vLabel'});
119+
dataTable.addColumn({type: 'string', id: 'hLabel'});
120+
dataTable.addColumn({type: 'string', role: 'style' });
121+
dataTable.addColumn({type: 'date', id: 'date_start'});
122+
dataTable.addColumn({type: 'date', id: 'date_end'});
123+
124+
dataTable.addRows([
125+
"@
126+
}
127+
128+
process {
129+
# build html container
130+
$BaseObject = $InputObject.PsObject.BaseObject
131+
132+
# create server list to support multiple servers
133+
if ($InputObject[0].SqlInstance -notin $servers) {
134+
$servers += $InputObject[0].SqlInstance
135+
}
136+
# This is where do column mapping.
137+
138+
# Check for types - this will help support if someone assigns a variable then pipes
139+
# AgentJobHistory is a forced type while backuphistory is a legit type
140+
if ($InputObject[0].TypeName -eq 'AgentJobHistory') {
141+
$CallerName = "Get-DbaAgentJobHistory"
142+
$data = $InputObject | Select-Object @{ Name = "SqlInstance"; Expression = { $_.SqlInstance } }, @{ Name = "InstanceName"; Expression = { $_.InstanceName } }, @{ Name = "vLabel"; Expression = { $_.Job } }, @{ Name = "hLabel"; Expression = { $_.Status } }, @{ Name = "Style"; Expression = { $(Convert-DbaTimelineStatusColor($_.Status)) } }, @{ Name = "StartDate"; Expression = { $(ConvertTo-JsDate($_.StartDate)) } }, @{ Name = "EndDate"; Expression = { $(ConvertTo-JsDate($_.EndDate)) } }
143+
144+
}
145+
elseif ($InputObject[0] -is [Sqlcollaborative.Dbatools.Database.BackupHistory]) {
146+
$CallerName = "Get-DbaBackupHistory"
147+
$data = $InputObject | Select-Object @{ Name = "SqlInstance"; Expression = { $_.SqlInstance } }, @{ Name = "InstanceName"; Expression = { $_.InstanceName } }, @{ Name = "vLabel"; Expression = { $_.Database } }, @{ Name = "hLabel"; Expression = { $_.Type } }, @{ Name = "StartDate"; Expression = { $(ConvertTo-JsDate($_.Start)) } }, @{ Name = "EndDate"; Expression = { $(ConvertTo-JsDate($_.End)) } }
148+
}
149+
else {
150+
# sorry to be so formal, can't help it ;)
151+
Stop-Function -Message "Unsupported input data. To request support for additional commands, please file an issue at dbatools.io/issues and we'll take a look"
152+
return
153+
}
154+
$body += "$($data | ForEach-Object{ "['$($_.vLabel)','$($_.hLabel)','$($_.Style)',$($_.StartDate), $($_.EndDate)]," })"
155+
}
156+
end {
157+
if (Test-FunctionInterrupt) { return }
158+
$end = @"
159+
]);
160+
var paddingHeight = 20;
161+
var rowHeight = dataTable.getNumberOfRows() * 41;
162+
var chartHeight = rowHeight + paddingHeight;
163+
dataTable.insertColumn(2, {type: 'string', role: 'tooltip', p: {html: true}});
164+
var dateFormat = new google.visualization.DateFormat({
165+
pattern: 'dd/MM/yy HH:mm:ss'
166+
});
167+
for (var i = 0; i < dataTable.getNumberOfRows(); i++) {
168+
var duration = (dataTable.getValue(i, 5).getTime() - dataTable.getValue(i, 4).getTime()) / 1000;
169+
var hours = parseInt( duration / 3600 ) % 24;
170+
var minutes = parseInt( duration / 60 ) % 60;
171+
var seconds = duration % 60;
172+
var tooltip = '<div class="timeline-tooltip"><span>' +
173+
dataTable.getValue(i, 1).split(",").join("<br />") + '</span></div><div class="timeline-tooltip"><span>' +
174+
dataTable.getValue(i, 0) + '</span>: ' +
175+
dateFormat.formatValue(dataTable.getValue(i, 4)) + ' - ' +
176+
dateFormat.formatValue(dataTable.getValue(i, 5)) + '</div>' +
177+
'<div class="timeline-tooltip"><span>Duration: </span>' +
178+
hours + 'h ' + minutes + 'm ' + seconds + 's ';
179+
dataTable.setValue(i, 2, tooltip);
180+
}
181+
var options = {
182+
timeline: {
183+
rowLabelStyle: { },
184+
barLabelStyle: { },
185+
},
186+
hAxis: {
187+
format: 'dd/MM HH:mm',
188+
},
189+
}
190+
// Autosize chart. It would not be enough to just count rows and expand based on row height as there can be overlappig rows.
191+
// this will draw the chart, get the size of the underlying div and apply that size to the parent container and redraw:
192+
chart.draw(dataTable, options);
193+
// get the size of the chold div:
194+
var realheight= parseInt(`$("#Chart div:first-child div:first-child div:first-child div svg").attr( "height"))+70;
195+
// set the height:
196+
options.height=realheight
197+
// draw again:
198+
chart.draw(dataTable, options);
199+
}
200+
</script>
201+
</head>
202+
<body>
203+
<div class="container-fluid">
204+
<div class="pull-left"><h3><code>$($CallerName)</code> timeline for server <code>$($servers -join ', ')</code></h3></div><div class="pull-right text-right"><img class="text-right" style="vertical-align:bottom; margin-top: 10px;" src="https://dbatools.io/wp-content/uploads/2016/05/dbatools-logo-1.png" width=150></div>
205+
<div class="clearfix"></div>
206+
<div class="col-12">
207+
<div class="chart" id="Chart"></div>
208+
</div>
209+
<hr>
210+
<p><a href="https://dbatools.io">dbatools.io</a> - the community's sql powershell module. Find us on Twitter: <a href="https://twitter.com/psdbatools">@psdbatools</a> | Chart by <a href="https://twitter.com/marcingminski">@marcingminski</a></p>
211+
</div>
212+
</body>
213+
</html>
214+
"@
215+
$begin, $body, $end
216+
}
217+
}

‎functions/Get-DbaAgentJobHistory.ps1

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,10 +269,13 @@ function Get-DbaAgentJobHistory {
269269
}
270270
Add-Member -Force -InputObject $execution -MemberType NoteProperty -Name OutputFileName -value $outname
271271
Add-Member -Force -InputObject $execution -MemberType NoteProperty -Name RemoteOutputFileName -value $outremote
272-
Select-DefaultView -InputObject $execution -Property ComputerName, InstanceName, SqlInstance, 'JobName as Job', StepName, RunDate, StartDate, EndDate, Duration, Status, OperatorEmailed, Message, OutputFileName, RemoteOutputFileName
272+
# Add this in for easier ConvertTo-DbaTimeline Support
273+
Add-Member -Force -InputObject $execution -MemberType NoteProperty -Name TypeName -value AgentJobHistory
274+
Select-DefaultView -InputObject $execution -Property ComputerName, InstanceName, SqlInstance, 'JobName as Job', StepName, RunDate, StartDate, EndDate, Duration, Status, OperatorEmailed, Message, OutputFileName, RemoteOutputFileName -TypeName AgentJobHistory
273275
}
274276
else {
275-
Select-DefaultView -InputObject $execution -Property ComputerName, InstanceName, SqlInstance, 'JobName as Job', StepName, RunDate, StartDate, EndDate, Duration, Status, OperatorEmailed, Message
277+
Add-Member -Force -InputObject $execution -MemberType NoteProperty -Name TypeName -value AgentJobHistory
278+
Select-DefaultView -InputObject $execution -Property ComputerName, InstanceName, SqlInstance, 'JobName as Job', StepName, RunDate, StartDate, EndDate, Duration, Status, OperatorEmailed, Message -TypeName AgentJobHistory
276279
}
277280

278281
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
function Convert-DbaTimelineStatusColor {
2+
<#
3+
.SYNOPSIS
4+
Converts literal string status to a html color
5+
6+
.DESCRIPTION
7+
This function acceptes Agnet Job status as literal string input and covnerts to html color.
8+
This is internal function, part of ConvertTo-DbaTimeline
9+
10+
.PARAMETER Status
11+
12+
The Status input parameter must be a valid SQL Agent Job status as literal string as defined in MS Books:
13+
Status of the job execution:
14+
Failed
15+
Succeeded
16+
Retry
17+
Canceled
18+
In Progress
19+
20+
.NOTES
21+
Tags: Internal
22+
Author: Marcin Gminski (@marcingminski)
23+
24+
Dependency: None
25+
Requirements: None
26+
27+
Website: https://dbatools.io
28+
Copyright: (C) Chrissy LeMaire, clemaire@gmail.com
29+
- License: MIT https://opensource.org/licenses/MIT
30+
31+
.LINK
32+
--internal function, not exposed to end user
33+
34+
.EXAMPLE
35+
Convert-DbaTimelineStatusColor ("Succeeded")
36+
37+
Returned string: #36B300
38+
#>
39+
40+
[CmdletBinding()]
41+
param (
42+
[Parameter(Mandatory = $true)]
43+
[string]
44+
$Status
45+
)
46+
$out = switch($Status){
47+
"Failed" {"#FF3D3D"}
48+
"Succeeded" {"#36B300"}
49+
"Retry" {"#FFFF00"}
50+
"Canceled" {"#C2C2C2"}
51+
"In Progress" {"#00CCFF"}
52+
default {"#FF00CC"}
53+
}
54+
return $out
55+
}

‎internal/functions/ConvertTo-JsDate.ps1

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
function ConvertTo-JsDate {
2+
<#
3+
.SYNOPSIS
4+
Converts Datetime input to a Java Script date format
5+
6+
.DESCRIPTION
7+
This function acceptes date time input and converts to a Java script compatible format.
8+
Java Script date time format:
9+
New date (yyyy, MM, dd, HH, mm, ss)
10+
11+
This is internal function part of ConvertTo-DbaTimeline
12+
13+
.PARAMETER InputDate
14+
15+
The InputDate parameter must be a valid datetime type
16+
17+
.NOTES
18+
Tags: Internal
19+
Author: Marcin Gminski (@marcingminski)
20+
21+
Dependency: None
22+
Requirements: None
23+
24+
Website: https://dbatools.io
25+
Copyright: (C) Chrissy LeMaire, clemaire@gmail.com
26+
- License: MIT https://opensource.org/licenses/MIT
27+
28+
.LINK
29+
--internal function, not exposed to end user
30+
31+
.EXAMPLE
32+
ConvertTo-JsDate (Get-Date)
33+
34+
Returned output: new Date(2018, 7, 14, 07, 40, 42)
35+
#>
36+
37+
[CmdletBinding()]
38+
param (
39+
[Parameter(Mandatory = $true)]
40+
[datetime]
41+
$InputDate
42+
)
43+
[string]$out = "new Date($(Get-Date $InputDate -format "yyyy"), $($(Get-Date $InputDate -format "MM")-1), $(Get-Date $InputDate -format "dd"), $(Get-Date $InputDate -format "HH"), $(Get-Date $InputDate -format "mm"), $(Get-Date $InputDate -format "ss"))"
44+
return $out
45+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /