├── .swift-version
├── docs
├── img
│ ├── dash.png
│ ├── gh.png
│ ├── carat.png
│ └── spinner.gif
├── docsets
│ ├── Health.tgz
│ └── Health.docset
│ │ └── Contents
│ │ ├── Resources
│ │ ├── docSet.dsidx
│ │ └── Documents
│ │ │ ├── img
│ │ │ ├── gh.png
│ │ │ ├── carat.png
│ │ │ ├── dash.png
│ │ │ └── spinner.gif
│ │ │ ├── js
│ │ │ ├── jazzy.js
│ │ │ └── jazzy.search.js
│ │ │ ├── css
│ │ │ ├── highlight.css
│ │ │ └── jazzy.css
│ │ │ ├── Structs.html
│ │ │ ├── Extensions.html
│ │ │ ├── Typealiases.html
│ │ │ ├── search.json
│ │ │ ├── Enums.html
│ │ │ ├── Protocols.html
│ │ │ ├── Enums
│ │ │ ├── State.html
│ │ │ └── InvalidDataError.html
│ │ │ └── Extensions
│ │ │ └── Date.html
│ │ └── Info.plist
├── undocumented.json
├── badge.svg
├── js
│ ├── jazzy.js
│ └── jazzy.search.js
├── css
│ ├── highlight.css
│ └── jazzy.css
├── Structs.html
├── Extensions.html
├── Typealiases.html
├── search.json
├── Enums.html
├── Protocols.html
├── Enums
│ ├── State.html
│ └── InvalidDataError.html
└── Extensions
│ └── Date.html
├── .gitignore
├── docker-compose.yml
├── .jazzy.yaml
├── Tests
├── LinuxMain.swift
└── HealthTests
│ └── HealthTests.swift
├── Sources
└── Health
│ ├── Utils.swift
│ ├── Health.swift
│ └── Protocols.swift
├── Package.swift
├── Package@swift-4.swift
├── .travis.yml
└── README.md
/.swift-version:
--------------------------------------------------------------------------------
1 | 5.1
2 |
--------------------------------------------------------------------------------
/docs/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitura/Health/HEAD/docs/img/dash.png
--------------------------------------------------------------------------------
/docs/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitura/Health/HEAD/docs/img/gh.png
--------------------------------------------------------------------------------
/docs/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitura/Health/HEAD/docs/img/carat.png
--------------------------------------------------------------------------------
/docs/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitura/Health/HEAD/docs/img/spinner.gif
--------------------------------------------------------------------------------
/docs/docsets/Health.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitura/Health/HEAD/docs/docsets/Health.tgz
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build/*
3 | /.build-ubuntu/*
4 | /*.xcodeproj
5 | build/*
6 | Package.resolved
7 |
--------------------------------------------------------------------------------
/docs/undocumented.json:
--------------------------------------------------------------------------------
1 | {
2 | "warnings": [
3 |
4 | ],
5 | "source_directory": "/Users/travis/build/IBM-Swift/Health"
6 | }
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/docSet.dsidx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitura/Health/HEAD/docs/docsets/Health.docset/Contents/Resources/docSet.dsidx
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitura/Health/HEAD/docs/docsets/Health.docset/Contents/Resources/Documents/img/gh.png
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitura/Health/HEAD/docs/docsets/Health.docset/Contents/Resources/Documents/img/carat.png
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitura/Health/HEAD/docs/docsets/Health.docset/Contents/Resources/Documents/img/dash.png
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitura/Health/HEAD/docs/docsets/Health.docset/Contents/Resources/Documents/img/spinner.gif
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | # docker-compose up
2 | app:
3 | image: ibmcom/swift-ubuntu:4.0
4 | volumes:
5 | - .:/Health
6 | command: bash -c "cd /Health && swift package --build-path .build-ubuntu clean && swift build --build-path .build-ubuntu && swift test --build-path .build-ubuntu"
7 |
--------------------------------------------------------------------------------
/.jazzy.yaml:
--------------------------------------------------------------------------------
1 | module: Health
2 | author: IBM and the Kitura project authors
3 | github_url: https://github.com/Kitura/Health/
4 |
5 | theme: fullwidth
6 | clean: true
7 | exclude: [Packages]
8 |
9 | readme: README.md
10 |
11 | skip_undocumented: false
12 | hide_documentation_coverage: false
13 |
14 | xcodebuild_arguments: [-project, Health.xcodeproj, -target, Health, LIBRARY_SEARCH_PATHS=.build/debug]
15 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | com.jazzy.health
7 | CFBundleName
8 | Health
9 | DocSetPlatformFamily
10 | health
11 | isDashDocset
12 |
13 | dashIndexFilePath
14 | index.html
15 | isJavaScriptEnabled
16 |
17 | DashDocSetFamily
18 | dashtoc
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright IBM Corporation 2017
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | import XCTest
18 | @testable import HealthTests
19 |
20 | XCTMain([
21 | testCase(HealthTests.allTests),
22 | ])
23 |
--------------------------------------------------------------------------------
/docs/badge.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | documentation
17 |
18 |
19 | documentation
20 |
21 |
22 | 100%
23 |
24 |
25 | 100%
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Sources/Health/Utils.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright IBM Corporation 2017
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | import Foundation
18 |
19 | /// Extension to the `Date` type.
20 | extension Date {
21 |
22 | /// Returns the current time in milliseconds.
23 | public static func currentTimeMillis() -> UInt64 {
24 | let timeInMillis = UInt64(NSDate().timeIntervalSince1970 * 1000.0)
25 | return timeInMillis
26 | }
27 |
28 | /// Returns the time value of the date in milliseconds (since 1970).
29 | var milliseconds: UInt64 {
30 | get {
31 | return UInt64(self.timeIntervalSince1970 * 1000.0)
32 | }
33 | }
34 |
35 | /// Creates a `Date` instance from milliseconds.
36 | public init(timeInMillis: UInt64) {
37 | self = Date(timeIntervalSince1970: TimeInterval(timeInMillis / 1000))
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/docs/js/jazzy.js:
--------------------------------------------------------------------------------
1 | window.jazzy = {'docset': false}
2 | if (typeof window.dash != 'undefined') {
3 | document.documentElement.className += ' dash'
4 | window.jazzy.docset = true
5 | }
6 | if (navigator.userAgent.match(/xcode/i)) {
7 | document.documentElement.className += ' xcode'
8 | window.jazzy.docset = true
9 | }
10 |
11 | // On doc load, toggle the URL hash discussion if present
12 | $(document).ready(function() {
13 | if (!window.jazzy.docset) {
14 | var linkToHash = $('a[href="' + window.location.hash +'"]');
15 | linkToHash.trigger("click");
16 | }
17 | });
18 |
19 | // On token click, toggle its discussion and animate token.marginLeft
20 | $(".token").click(function(event) {
21 | if (window.jazzy.docset) {
22 | return;
23 | }
24 | var link = $(this);
25 | var animationDuration = 300;
26 | $content = link.parent().parent().next();
27 | $content.slideToggle(animationDuration);
28 |
29 | // Keeps the document from jumping to the hash.
30 | var href = $(this).attr('href');
31 | if (history.pushState) {
32 | history.pushState({}, '', href);
33 | } else {
34 | location.hash = href;
35 | }
36 | event.preventDefault();
37 | });
38 |
39 | // Dumb down quotes within code blocks that delimit strings instead of quotations
40 | // https://github.com/realm/jazzy/issues/714
41 | $("code q").replaceWith(function () {
42 | return ["\"", $(this).contents(), "\""];
43 | });
44 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/js/jazzy.js:
--------------------------------------------------------------------------------
1 | window.jazzy = {'docset': false}
2 | if (typeof window.dash != 'undefined') {
3 | document.documentElement.className += ' dash'
4 | window.jazzy.docset = true
5 | }
6 | if (navigator.userAgent.match(/xcode/i)) {
7 | document.documentElement.className += ' xcode'
8 | window.jazzy.docset = true
9 | }
10 |
11 | // On doc load, toggle the URL hash discussion if present
12 | $(document).ready(function() {
13 | if (!window.jazzy.docset) {
14 | var linkToHash = $('a[href="' + window.location.hash +'"]');
15 | linkToHash.trigger("click");
16 | }
17 | });
18 |
19 | // On token click, toggle its discussion and animate token.marginLeft
20 | $(".token").click(function(event) {
21 | if (window.jazzy.docset) {
22 | return;
23 | }
24 | var link = $(this);
25 | var animationDuration = 300;
26 | $content = link.parent().parent().next();
27 | $content.slideToggle(animationDuration);
28 |
29 | // Keeps the document from jumping to the hash.
30 | var href = $(this).attr('href');
31 | if (history.pushState) {
32 | history.pushState({}, '', href);
33 | } else {
34 | location.hash = href;
35 | }
36 | event.preventDefault();
37 | });
38 |
39 | // Dumb down quotes within code blocks that delimit strings instead of quotations
40 | // https://github.com/realm/jazzy/issues/714
41 | $("code q").replaceWith(function () {
42 | return ["\"", $(this).contents(), "\""];
43 | });
44 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | /*
3 | * Copyright IBM Corporation and the Kitura project authors 2017-2020
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | import PackageDescription
19 |
20 | let package = Package(
21 | name: "Health",
22 | products: [
23 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
24 | .library(
25 | name: "Health",
26 | targets: ["Health"]
27 | ),
28 | ],
29 | dependencies: [
30 | .package(url: "https://github.com/Kitura/LoggerAPI.git", .upToNextMajor(from: "1.9.200")),
31 | ],
32 | targets: [
33 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
34 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
35 | // CRUD and CRUD tests removed until the files compile
36 | .target(
37 | name: "Health",
38 | dependencies: ["LoggerAPI"]
39 | ),
40 | .testTarget(
41 | name: "HealthTests",
42 | dependencies: ["Health"]
43 | ),
44 | ]
45 | )
46 |
--------------------------------------------------------------------------------
/Package@swift-4.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:4.0
2 | /*
3 | * Copyright IBM Corporation and the Kitura project authors 2017-2020
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | import PackageDescription
19 |
20 | let package = Package(
21 | name: "Health",
22 | products: [
23 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
24 | .library(
25 | name: "Health",
26 | targets: ["Health"]
27 | ),
28 | ],
29 | dependencies: [
30 | .package(url: "https://github.com/Kitura/LoggerAPI.git", .upToNextMajor(from: "1.9.200")),
31 | ],
32 | targets: [
33 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
34 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
35 | // CRUD and CRUD tests removed until the files compile
36 | .target(
37 | name: "Health",
38 | dependencies: ["LoggerAPI"]
39 | ),
40 | .testTarget(
41 | name: "HealthTests",
42 | dependencies: ["Health"]
43 | ),
44 | ]
45 | )
46 |
--------------------------------------------------------------------------------
/docs/js/jazzy.search.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | var searchIndex = lunr(function() {
3 | this.ref('url');
4 | this.field('name');
5 | });
6 |
7 | var $typeahead = $('[data-typeahead]');
8 | var $form = $typeahead.parents('form');
9 | var searchURL = $form.attr('action');
10 |
11 | function displayTemplate(result) {
12 | return result.name;
13 | }
14 |
15 | function suggestionTemplate(result) {
16 | var t = '
';
17 | t += '' + result.name + ' ';
18 | if (result.parent_name) {
19 | t += '' + result.parent_name + ' ';
20 | }
21 | t += '
';
22 | return t;
23 | }
24 |
25 | $typeahead.one('focus', function() {
26 | $form.addClass('loading');
27 |
28 | $.getJSON(searchURL).then(function(searchData) {
29 | $.each(searchData, function (url, doc) {
30 | searchIndex.add({url: url, name: doc.name});
31 | });
32 |
33 | $typeahead.typeahead(
34 | {
35 | highlight: true,
36 | minLength: 3
37 | },
38 | {
39 | limit: 10,
40 | display: displayTemplate,
41 | templates: { suggestion: suggestionTemplate },
42 | source: function(query, sync) {
43 | var results = searchIndex.search(query).map(function(result) {
44 | var doc = searchData[result.ref];
45 | doc.url = result.ref;
46 | return doc;
47 | });
48 | sync(results);
49 | }
50 | }
51 | );
52 | $form.removeClass('loading');
53 | $typeahead.trigger('focus');
54 | });
55 | });
56 |
57 | var baseURL = searchURL.slice(0, -"search.json".length);
58 |
59 | $typeahead.on('typeahead:select', function(e, result) {
60 | window.location = baseURL + result.url;
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/js/jazzy.search.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | var searchIndex = lunr(function() {
3 | this.ref('url');
4 | this.field('name');
5 | });
6 |
7 | var $typeahead = $('[data-typeahead]');
8 | var $form = $typeahead.parents('form');
9 | var searchURL = $form.attr('action');
10 |
11 | function displayTemplate(result) {
12 | return result.name;
13 | }
14 |
15 | function suggestionTemplate(result) {
16 | var t = '';
17 | t += '' + result.name + ' ';
18 | if (result.parent_name) {
19 | t += '' + result.parent_name + ' ';
20 | }
21 | t += '
';
22 | return t;
23 | }
24 |
25 | $typeahead.one('focus', function() {
26 | $form.addClass('loading');
27 |
28 | $.getJSON(searchURL).then(function(searchData) {
29 | $.each(searchData, function (url, doc) {
30 | searchIndex.add({url: url, name: doc.name});
31 | });
32 |
33 | $typeahead.typeahead(
34 | {
35 | highlight: true,
36 | minLength: 3
37 | },
38 | {
39 | limit: 10,
40 | display: displayTemplate,
41 | templates: { suggestion: suggestionTemplate },
42 | source: function(query, sync) {
43 | var results = searchIndex.search(query).map(function(result) {
44 | var doc = searchData[result.ref];
45 | doc.url = result.ref;
46 | return doc;
47 | });
48 | sync(results);
49 | }
50 | }
51 | );
52 | $form.removeClass('loading');
53 | $typeahead.trigger('focus');
54 | });
55 | });
56 |
57 | var baseURL = searchURL.slice(0, -"search.json".length);
58 |
59 | $typeahead.on('typeahead:select', function(e, result) {
60 | window.location = baseURL + result.url;
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Travis CI build file.
2 |
3 | # whitelist (branches that should be built)
4 | branches:
5 | only:
6 | - master
7 | - /^issue.*$/
8 |
9 | # the matrix of builds should cover each combination of Swift version
10 | # and platform that is supported. The version of Swift used is specified
11 | # by .swift-version, unless SWIFT_SNAPSHOT is specified.
12 | matrix:
13 | include:
14 | - os: linux
15 | dist: xenial
16 | sudo: required
17 | services: docker
18 | env: DOCKER_IMAGE=swift:4.0.3 SWIFT_SNAPSHOT=4.0.3
19 | - os: linux
20 | dist: xenial
21 | sudo: required
22 | services: docker
23 | env: DOCKER_IMAGE=swift:4.1.3 SWIFT_SNAPSHOT=4.1.3
24 | - os: linux
25 | dist: xenial
26 | sudo: required
27 | services: docker
28 | env: DOCKER_IMAGE=swift:4.2.4 SWIFT_SNAPSHOT=4.2.4
29 | - os: linux
30 | dist: xenial
31 | sudo: required
32 | services: docker
33 | env: DOCKER_IMAGE=swift:5.0.3-xenial SWIFT_SNAPSHOT=5.0.3
34 | - os: linux
35 | dist: xenial
36 | sudo: required
37 | services: docker
38 | env: DOCKER_IMAGE=swift:5.1
39 | - os: linux
40 | dist: xenial
41 | sudo: required
42 | services: docker
43 | env: DOCKER_IMAGE=swift:5.1 SWIFT_SNAPSHOT=$SWIFT_DEVELOPMENT_SNAPSHOT
44 | - os: osx
45 | osx_image: xcode9.2
46 | sudo: required
47 | env: SWIFT_SNAPSHOT=4.0.3
48 | - os: osx
49 | osx_image: xcode9.4
50 | sudo: required
51 | env: SWIFT_SNAPSHOT=4.1.2
52 | - os: osx
53 | osx_image: xcode10.1
54 | sudo: required
55 | env: SWIFT_SNAPSHOT=4.2.1
56 | - os: osx
57 | osx_image: xcode10.2
58 | sudo: required
59 | env: SWIFT_SNAPSHOT=5.0.1 JAZZY_ELIGIBLE=true
60 | - os: osx
61 | osx_image: xcode11
62 | sudo: required
63 | - os: osx
64 | osx_image: xcode11
65 | sudo: required
66 | env: SWIFT_SNAPSHOT=$SWIFT_DEVELOPMENT_SNAPSHOT
67 |
68 | before_install:
69 | - git clone https://github.com/Kitura/Package-Builder.git
70 |
71 | script:
72 | - ./Package-Builder/build-package.sh -projectDir $TRAVIS_BUILD_DIR
73 |
--------------------------------------------------------------------------------
/docs/css/highlight.css:
--------------------------------------------------------------------------------
1 | /* Credit to https://gist.github.com/wataru420/2048287 */
2 | .highlight {
3 | /* Comment */
4 | /* Error */
5 | /* Keyword */
6 | /* Operator */
7 | /* Comment.Multiline */
8 | /* Comment.Preproc */
9 | /* Comment.Single */
10 | /* Comment.Special */
11 | /* Generic.Deleted */
12 | /* Generic.Deleted.Specific */
13 | /* Generic.Emph */
14 | /* Generic.Error */
15 | /* Generic.Heading */
16 | /* Generic.Inserted */
17 | /* Generic.Inserted.Specific */
18 | /* Generic.Output */
19 | /* Generic.Prompt */
20 | /* Generic.Strong */
21 | /* Generic.Subheading */
22 | /* Generic.Traceback */
23 | /* Keyword.Constant */
24 | /* Keyword.Declaration */
25 | /* Keyword.Pseudo */
26 | /* Keyword.Reserved */
27 | /* Keyword.Type */
28 | /* Literal.Number */
29 | /* Literal.String */
30 | /* Name.Attribute */
31 | /* Name.Builtin */
32 | /* Name.Class */
33 | /* Name.Constant */
34 | /* Name.Entity */
35 | /* Name.Exception */
36 | /* Name.Function */
37 | /* Name.Namespace */
38 | /* Name.Tag */
39 | /* Name.Variable */
40 | /* Operator.Word */
41 | /* Text.Whitespace */
42 | /* Literal.Number.Float */
43 | /* Literal.Number.Hex */
44 | /* Literal.Number.Integer */
45 | /* Literal.Number.Oct */
46 | /* Literal.String.Backtick */
47 | /* Literal.String.Char */
48 | /* Literal.String.Doc */
49 | /* Literal.String.Double */
50 | /* Literal.String.Escape */
51 | /* Literal.String.Heredoc */
52 | /* Literal.String.Interpol */
53 | /* Literal.String.Other */
54 | /* Literal.String.Regex */
55 | /* Literal.String.Single */
56 | /* Literal.String.Symbol */
57 | /* Name.Builtin.Pseudo */
58 | /* Name.Variable.Class */
59 | /* Name.Variable.Global */
60 | /* Name.Variable.Instance */
61 | /* Literal.Number.Integer.Long */ }
62 | .highlight .c {
63 | color: #999988;
64 | font-style: italic; }
65 | .highlight .err {
66 | color: #a61717;
67 | background-color: #e3d2d2; }
68 | .highlight .k {
69 | color: #000000;
70 | font-weight: bold; }
71 | .highlight .o {
72 | color: #000000;
73 | font-weight: bold; }
74 | .highlight .cm {
75 | color: #999988;
76 | font-style: italic; }
77 | .highlight .cp {
78 | color: #999999;
79 | font-weight: bold; }
80 | .highlight .c1 {
81 | color: #999988;
82 | font-style: italic; }
83 | .highlight .cs {
84 | color: #999999;
85 | font-weight: bold;
86 | font-style: italic; }
87 | .highlight .gd {
88 | color: #000000;
89 | background-color: #ffdddd; }
90 | .highlight .gd .x {
91 | color: #000000;
92 | background-color: #ffaaaa; }
93 | .highlight .ge {
94 | color: #000000;
95 | font-style: italic; }
96 | .highlight .gr {
97 | color: #aa0000; }
98 | .highlight .gh {
99 | color: #999999; }
100 | .highlight .gi {
101 | color: #000000;
102 | background-color: #ddffdd; }
103 | .highlight .gi .x {
104 | color: #000000;
105 | background-color: #aaffaa; }
106 | .highlight .go {
107 | color: #888888; }
108 | .highlight .gp {
109 | color: #555555; }
110 | .highlight .gs {
111 | font-weight: bold; }
112 | .highlight .gu {
113 | color: #aaaaaa; }
114 | .highlight .gt {
115 | color: #aa0000; }
116 | .highlight .kc {
117 | color: #000000;
118 | font-weight: bold; }
119 | .highlight .kd {
120 | color: #000000;
121 | font-weight: bold; }
122 | .highlight .kp {
123 | color: #000000;
124 | font-weight: bold; }
125 | .highlight .kr {
126 | color: #000000;
127 | font-weight: bold; }
128 | .highlight .kt {
129 | color: #445588; }
130 | .highlight .m {
131 | color: #009999; }
132 | .highlight .s {
133 | color: #d14; }
134 | .highlight .na {
135 | color: #008080; }
136 | .highlight .nb {
137 | color: #0086B3; }
138 | .highlight .nc {
139 | color: #445588;
140 | font-weight: bold; }
141 | .highlight .no {
142 | color: #008080; }
143 | .highlight .ni {
144 | color: #800080; }
145 | .highlight .ne {
146 | color: #990000;
147 | font-weight: bold; }
148 | .highlight .nf {
149 | color: #990000; }
150 | .highlight .nn {
151 | color: #555555; }
152 | .highlight .nt {
153 | color: #000080; }
154 | .highlight .nv {
155 | color: #008080; }
156 | .highlight .ow {
157 | color: #000000;
158 | font-weight: bold; }
159 | .highlight .w {
160 | color: #bbbbbb; }
161 | .highlight .mf {
162 | color: #009999; }
163 | .highlight .mh {
164 | color: #009999; }
165 | .highlight .mi {
166 | color: #009999; }
167 | .highlight .mo {
168 | color: #009999; }
169 | .highlight .sb {
170 | color: #d14; }
171 | .highlight .sc {
172 | color: #d14; }
173 | .highlight .sd {
174 | color: #d14; }
175 | .highlight .s2 {
176 | color: #d14; }
177 | .highlight .se {
178 | color: #d14; }
179 | .highlight .sh {
180 | color: #d14; }
181 | .highlight .si {
182 | color: #d14; }
183 | .highlight .sx {
184 | color: #d14; }
185 | .highlight .sr {
186 | color: #009926; }
187 | .highlight .s1 {
188 | color: #d14; }
189 | .highlight .ss {
190 | color: #990073; }
191 | .highlight .bp {
192 | color: #999999; }
193 | .highlight .vc {
194 | color: #008080; }
195 | .highlight .vg {
196 | color: #008080; }
197 | .highlight .vi {
198 | color: #008080; }
199 | .highlight .il {
200 | color: #009999; }
201 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/css/highlight.css:
--------------------------------------------------------------------------------
1 | /* Credit to https://gist.github.com/wataru420/2048287 */
2 | .highlight {
3 | /* Comment */
4 | /* Error */
5 | /* Keyword */
6 | /* Operator */
7 | /* Comment.Multiline */
8 | /* Comment.Preproc */
9 | /* Comment.Single */
10 | /* Comment.Special */
11 | /* Generic.Deleted */
12 | /* Generic.Deleted.Specific */
13 | /* Generic.Emph */
14 | /* Generic.Error */
15 | /* Generic.Heading */
16 | /* Generic.Inserted */
17 | /* Generic.Inserted.Specific */
18 | /* Generic.Output */
19 | /* Generic.Prompt */
20 | /* Generic.Strong */
21 | /* Generic.Subheading */
22 | /* Generic.Traceback */
23 | /* Keyword.Constant */
24 | /* Keyword.Declaration */
25 | /* Keyword.Pseudo */
26 | /* Keyword.Reserved */
27 | /* Keyword.Type */
28 | /* Literal.Number */
29 | /* Literal.String */
30 | /* Name.Attribute */
31 | /* Name.Builtin */
32 | /* Name.Class */
33 | /* Name.Constant */
34 | /* Name.Entity */
35 | /* Name.Exception */
36 | /* Name.Function */
37 | /* Name.Namespace */
38 | /* Name.Tag */
39 | /* Name.Variable */
40 | /* Operator.Word */
41 | /* Text.Whitespace */
42 | /* Literal.Number.Float */
43 | /* Literal.Number.Hex */
44 | /* Literal.Number.Integer */
45 | /* Literal.Number.Oct */
46 | /* Literal.String.Backtick */
47 | /* Literal.String.Char */
48 | /* Literal.String.Doc */
49 | /* Literal.String.Double */
50 | /* Literal.String.Escape */
51 | /* Literal.String.Heredoc */
52 | /* Literal.String.Interpol */
53 | /* Literal.String.Other */
54 | /* Literal.String.Regex */
55 | /* Literal.String.Single */
56 | /* Literal.String.Symbol */
57 | /* Name.Builtin.Pseudo */
58 | /* Name.Variable.Class */
59 | /* Name.Variable.Global */
60 | /* Name.Variable.Instance */
61 | /* Literal.Number.Integer.Long */ }
62 | .highlight .c {
63 | color: #999988;
64 | font-style: italic; }
65 | .highlight .err {
66 | color: #a61717;
67 | background-color: #e3d2d2; }
68 | .highlight .k {
69 | color: #000000;
70 | font-weight: bold; }
71 | .highlight .o {
72 | color: #000000;
73 | font-weight: bold; }
74 | .highlight .cm {
75 | color: #999988;
76 | font-style: italic; }
77 | .highlight .cp {
78 | color: #999999;
79 | font-weight: bold; }
80 | .highlight .c1 {
81 | color: #999988;
82 | font-style: italic; }
83 | .highlight .cs {
84 | color: #999999;
85 | font-weight: bold;
86 | font-style: italic; }
87 | .highlight .gd {
88 | color: #000000;
89 | background-color: #ffdddd; }
90 | .highlight .gd .x {
91 | color: #000000;
92 | background-color: #ffaaaa; }
93 | .highlight .ge {
94 | color: #000000;
95 | font-style: italic; }
96 | .highlight .gr {
97 | color: #aa0000; }
98 | .highlight .gh {
99 | color: #999999; }
100 | .highlight .gi {
101 | color: #000000;
102 | background-color: #ddffdd; }
103 | .highlight .gi .x {
104 | color: #000000;
105 | background-color: #aaffaa; }
106 | .highlight .go {
107 | color: #888888; }
108 | .highlight .gp {
109 | color: #555555; }
110 | .highlight .gs {
111 | font-weight: bold; }
112 | .highlight .gu {
113 | color: #aaaaaa; }
114 | .highlight .gt {
115 | color: #aa0000; }
116 | .highlight .kc {
117 | color: #000000;
118 | font-weight: bold; }
119 | .highlight .kd {
120 | color: #000000;
121 | font-weight: bold; }
122 | .highlight .kp {
123 | color: #000000;
124 | font-weight: bold; }
125 | .highlight .kr {
126 | color: #000000;
127 | font-weight: bold; }
128 | .highlight .kt {
129 | color: #445588; }
130 | .highlight .m {
131 | color: #009999; }
132 | .highlight .s {
133 | color: #d14; }
134 | .highlight .na {
135 | color: #008080; }
136 | .highlight .nb {
137 | color: #0086B3; }
138 | .highlight .nc {
139 | color: #445588;
140 | font-weight: bold; }
141 | .highlight .no {
142 | color: #008080; }
143 | .highlight .ni {
144 | color: #800080; }
145 | .highlight .ne {
146 | color: #990000;
147 | font-weight: bold; }
148 | .highlight .nf {
149 | color: #990000; }
150 | .highlight .nn {
151 | color: #555555; }
152 | .highlight .nt {
153 | color: #000080; }
154 | .highlight .nv {
155 | color: #008080; }
156 | .highlight .ow {
157 | color: #000000;
158 | font-weight: bold; }
159 | .highlight .w {
160 | color: #bbbbbb; }
161 | .highlight .mf {
162 | color: #009999; }
163 | .highlight .mh {
164 | color: #009999; }
165 | .highlight .mi {
166 | color: #009999; }
167 | .highlight .mo {
168 | color: #009999; }
169 | .highlight .sb {
170 | color: #d14; }
171 | .highlight .sc {
172 | color: #d14; }
173 | .highlight .sd {
174 | color: #d14; }
175 | .highlight .s2 {
176 | color: #d14; }
177 | .highlight .se {
178 | color: #d14; }
179 | .highlight .sh {
180 | color: #d14; }
181 | .highlight .si {
182 | color: #d14; }
183 | .highlight .sx {
184 | color: #d14; }
185 | .highlight .sr {
186 | color: #009926; }
187 | .highlight .s1 {
188 | color: #d14; }
189 | .highlight .ss {
190 | color: #990073; }
191 | .highlight .bp {
192 | color: #999999; }
193 | .highlight .vc {
194 | color: #008080; }
195 | .highlight .vg {
196 | color: #008080; }
197 | .highlight .vi {
198 | color: #008080; }
199 | .highlight .il {
200 | color: #009999; }
201 |
--------------------------------------------------------------------------------
/Sources/Health/Health.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright IBM Corporation 2017
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | import Foundation
18 | import Dispatch
19 |
20 | /// The `Health` class provides a concrete implementation of the `HealthProtocol` protocol that
21 | /// applications can instantiate and then register one or more health checks against. Once you
22 | /// have your health checks in place you can ask your `Health` instance for its status.
23 | ///
24 | ///### Usage Example: ###
25 | /// One common use case for this Swift package is to integrate it into a Kitura-based application. In the code sample below, the health of the application is exposed through the /health endpoint. Cloud environments (e.g. Cloud Foundry, Kubernetes, etc.) can then use the status information returned from the /health endpoint to monitor and manage the Swift application instance.
26 | ///
27 | /// For further information and example code see our [README](https://github.com/IBM-Swift/Health/blob/master/README.md) and the [Cloud Foundry documentation for using application health checks](https://docs.cloudfoundry.org/devguide/deploy-apps/healthchecks.html).
28 | ///```swift
29 | /// import Health
30 | ///
31 | /// let health = Health()
32 | ///
33 | /// health.addCheck(check: MyCheck1())
34 | /// health.addCheck(check: myClosureCheck1)
35 | ///
36 | /// // Define /health endpoint that leverages Health
37 | /// router.get("/health") { request, response, next in
38 | /// let status = health.status
39 | /// if health.status.state == .UP {
40 | /// try response.status(.OK).send(status).end()
41 | /// } else {
42 | /// try response.status(.serviceUnavailable).send(status).end()
43 | /// }
44 | /// }
45 | ///```
46 | public class Health: HealthProtocol {
47 | private var checks: [HealthCheck]
48 | private var closureChecks: [HealthCheckClosure]
49 | private var lastStatus: Status
50 | private let statusExpirationTime: Int // milliseconds
51 | private let statusSemaphore = DispatchSemaphore(value: 1)
52 |
53 | /// Status instance variable.
54 | public var status: Status {
55 | get {
56 | statusSemaphore.wait()
57 | let current = Date.currentTimeMillis()
58 | let last = self.lastStatus.tsInMillis
59 |
60 | // If elapsed time is bigger than the status expiration window, re-compute status
61 | // Check if current > last to avoid crashs because of negative UInt64 values
62 | // This is possible because of different rounding behaviour of DateFormatter.string() and
63 | // timeIntervalSince1970 > UInt64 convertion
64 | if current > last && (current - last) > UInt64(statusExpirationTime) {
65 | forceUpdateStatus()
66 | }
67 | statusSemaphore.signal()
68 | return lastStatus
69 | }
70 | }
71 |
72 | /// Number of health checks registered.
73 | ///
74 | ///### Usage Example: ###
75 | ///```swift
76 | /// let health = Health()
77 | ///
78 | /// let count = health.numberOfChecks
79 | ///```
80 | public var numberOfChecks: Int {
81 | get {
82 | return (checks.count + closureChecks.count)
83 | }
84 | }
85 |
86 | /// Creates an instance of the `Health` class.
87 | ///
88 | ///### Usage Example: ###
89 | /// In the example below the `statusExpirationTime` defaults to `30000` milliseconds, in this
90 | /// case 30 seconds must elapse before the `Health` instance computes its status again by
91 | /// querying each health check that has been registered.
92 | ///```swift
93 | ///let health = Health()
94 | ///```
95 | /// - Parameter statusExpirationTime: Optional. The time window in milliseconds that should
96 | /// elapse before the status cache for this `Health` instance is considered to be expired
97 | /// and should be recomputed. The default value is `30000`.
98 | public init(statusExpirationTime: Int = 30000) {
99 | self.statusExpirationTime = statusExpirationTime
100 | self.lastStatus = Status(state: .UP)
101 | checks = [HealthCheck]()
102 | closureChecks = [HealthCheckClosure]()
103 | }
104 |
105 | /// Registers a health check.
106 | ///
107 | ///### Usage Example: ###
108 | ///```swift
109 | /// let health = Health()
110 | ///
111 | /// // Add custom checks
112 | /// health.addCheck(check: MyCheck1())
113 | ///```
114 | /// - Parameter check: An object that extends the `HealthCheck` class.
115 | public func addCheck(check: HealthCheck) {
116 | checks.append(check)
117 | }
118 |
119 | /// Registers a health check.
120 | ///
121 | ///### Usage Example: ###
122 | ///```swift
123 | /// let health = Health()
124 | ///
125 | /// // Add custom checks
126 | /// health.addCheck(check: myClosureCheck1)
127 | ///```
128 | /// - Parameter check: A closure that conforms to the `HealthCheckClosure` type alias.
129 | public func addCheck(check: @escaping HealthCheckClosure) {
130 | closureChecks.append(check)
131 | }
132 |
133 | /// Forces an update to the status of this instance.
134 | public func forceUpdateStatus() {
135 | let checksDetails = checks.map { $0.evaluate() == State.DOWN ? $0.description : nil }
136 | let closureChecksDetails = closureChecks.map { $0() == State.DOWN ? "A health check closure reported status as DOWN." : nil }
137 | #if swift(>=4.1)
138 | let details = (checksDetails + closureChecksDetails).compactMap { $0 }
139 | #else
140 | let details = (checksDetails + closureChecksDetails).flatMap { $0 }
141 | #endif
142 | let state = (details.isEmpty) ? State.UP : State.DOWN
143 | lastStatus = Status(state: state, details: details)
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/docs/Structs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Structures Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | Health Reference
45 |
46 | Structures Reference
47 |
48 |
49 |
50 |
51 |
110 |
111 |
112 |
113 |
114 |
115 |
Structures
116 |
The following structures are available globally.
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | Status
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
Struct that encapsulates the status of an application.
139 |
140 |
See more
141 |
142 |
143 |
Declaration
144 |
145 |
Swift
146 |
public struct Status : Equatable
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/Structs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Structures Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | Health Reference
45 |
46 | Structures Reference
47 |
48 |
49 |
50 |
51 |
110 |
111 |
112 |
113 |
114 |
115 |
Structures
116 |
The following structures are available globally.
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | Status
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
Struct that encapsulates the status of an application.
139 |
140 |
See more
141 |
142 |
143 |
Declaration
144 |
145 |
Swift
146 |
public struct Status : Equatable
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/Extensions.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Extensions Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | Health Reference
45 |
46 | Extensions Reference
47 |
48 |
49 |
50 |
51 |
110 |
111 |
112 |
113 |
114 |
115 |
Extensions
116 |
The following extensions are available globally.
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | Date
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
Extension to the Date type.
139 |
140 |
See more
141 |
142 |
143 |
Declaration
144 |
145 |
Swift
146 |
struct Date : ReferenceConvertible , Comparable , Equatable
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/Typealiases.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Type Aliases Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | Health Reference
45 |
46 | Type Aliases Reference
47 |
48 |
49 |
50 |
51 |
110 |
111 |
112 |
113 |
114 |
115 |
Type Aliases
116 |
The following type aliases are available globally.
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
133 |
134 |
135 |
136 |
137 |
138 |
HealthCheckClosure is a type alias for a closure that receives no arguments and
139 | returns a State value.
140 |
141 |
142 |
143 |
Declaration
144 |
145 |
Swift
146 |
public typealias HealthCheckClosure = () -> State
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/Extensions.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Extensions Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | Health Reference
45 |
46 | Extensions Reference
47 |
48 |
49 |
50 |
51 |
110 |
111 |
112 |
113 |
114 |
115 |
Extensions
116 |
The following extensions are available globally.
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | Date
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
Extension to the Date type.
139 |
140 |
See more
141 |
142 |
143 |
Declaration
144 |
145 |
Swift
146 |
struct Date : ReferenceConvertible , Comparable , Equatable
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/Typealiases.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Type Aliases Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | Health Reference
45 |
46 | Type Aliases Reference
47 |
48 |
49 |
50 |
51 |
110 |
111 |
112 |
113 |
114 |
115 |
Type Aliases
116 |
The following type aliases are available globally.
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
133 |
134 |
135 |
136 |
137 |
138 |
HealthCheckClosure is a type alias for a closure that receives no arguments and
139 | returns a State value.
140 |
141 |
142 |
143 |
Declaration
144 |
145 |
Swift
146 |
public typealias HealthCheckClosure = () -> State
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
164 |
165 |
166 |
167 |
--------------------------------------------------------------------------------
/docs/search.json:
--------------------------------------------------------------------------------
1 | {"Typealiases.html#/s:6Health0A12CheckClosurea":{"name":"HealthCheckClosure","abstract":"HealthCheckClosure is a type alias for a closure that receives no arguments and"},"Structs/Status.html#/s:6Health6StatusV13dateFormatterAA0b4DateD0CvpZ":{"name":"dateFormatter","abstract":"
The date formatter used by the Status struct.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV10dateFormatSSvpZ":{"name":"dateFormat","abstract":"The date format used by the timestamp value in the dictionary.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV5stateAA5StateOvp":{"name":"state","abstract":"The state value contained within this struct.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV7detailsSaySSGvp":{"name":"details","abstract":"List of details describing any failures.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV10tsInMilliss6UInt64Vvp":{"name":"tsInMillis","abstract":"The timestamp value in milliseconds for the status.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV9timestampSSvp":{"name":"timestamp","abstract":"The string timestamp value for the status.
","parent_name":"Status"},"Structs/Status.html#/s:s9EquatableP2eeoiSbx_xtFZ":{"name":"==(_:_:)","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusVAcA5StateO5state_SaySSG7detailsSS9timestamptcfc":{"name":"init(state:details:timestamp:)","abstract":"Initializes the Status struct, which encapsulates the status of an application.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV12toDictionarys0D0VySSypGyF":{"name":"toDictionary()","abstract":"Returns a dictionary that contains the current status information. This dictionary","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV18toSimpleDictionarys0E0VySSypGyF":{"name":"toSimpleDictionary()","abstract":"
Returns a simple dictionary that contains the current status information. This dictionary","parent_name":"Status"},"Structs/Status.html#/s:s9EncodableP6encodeys7Encoder_p2to_tKF":{"name":"encode(to:)","parent_name":"Status"},"Structs/Status.html#/s:s9DecodablePxs7Decoder_p4from_tKcfc":{"name":"init(from:)","parent_name":"Status"},"Structs/Status.html":{"name":"Status","abstract":"
Struct that encapsulates the status of an application.
"},"Protocols/HealthProtocol.html#/s:6Health0A8ProtocolP6statusAA6StatusVvp":{"name":"status","abstract":"Status instance variable.
","parent_name":"HealthProtocol"},"Protocols/HealthProtocol.html#/s:6Health0A8ProtocolP8addCheckyAA0aD0_p5check_tF":{"name":"addCheck(check:)","abstract":"Registers a health check.
","parent_name":"HealthProtocol"},"Protocols/HealthProtocol.html#/s:6Health0A8ProtocolP8addCheckyAA5StateOyc5check_tF":{"name":"addCheck(check:)","abstract":"Registers a health check.
","parent_name":"HealthProtocol"},"Protocols/HealthCheck.html#/s:6Health0A5CheckP4nameSSvp":{"name":"name","abstract":"Name for the health check.
","parent_name":"HealthCheck"},"Protocols/HealthCheck.html#/s:6Health0A5CheckP11descriptionSSvp":{"name":"description","abstract":"Description for the health check.
","parent_name":"HealthCheck"},"Protocols/HealthCheck.html#/s:6Health0A5CheckP8evaluateAA5StateOyF":{"name":"evaluate()","abstract":"Performs the health check test.
","parent_name":"HealthCheck"},"Protocols/HealthCheck.html":{"name":"HealthCheck","abstract":"Health check classes should extend this protocol to provide concrete implementations.
"},"Protocols/HealthProtocol.html":{"name":"HealthProtocol","abstract":"Specifies the blueprint that must be implemented to satisfy the needs of a Health class."},"Extensions/Date.html#/s:10Foundation4DateV6HealthE17currentTimeMilliss6UInt64VyFZ":{"name":"currentTimeMillis()","abstract":"
Returns the current time in milliseconds.
","parent_name":"Date"},"Extensions/Date.html#/s:10Foundation4DateV6HealthEACs6UInt64V12timeInMillis_tcfc":{"name":"init(timeInMillis:)","abstract":"Creates a Date instance from milliseconds.
","parent_name":"Date"},"Extensions/Date.html":{"name":"Date","abstract":"Extension to the Date type.
"},"Enums/State.html#/s:6Health5StateO2UPA2CmF":{"name":"UP","abstract":"Application is running just fine.
","parent_name":"State"},"Enums/State.html#/s:6Health5StateO4DOWNA2CmF":{"name":"DOWN","abstract":"Application health is not good.
","parent_name":"State"},"Enums/InvalidDataError.html#/s:6Health16InvalidDataErrorO15deserializationACSScACmF":{"name":"deserialization","abstract":"A deserialization error occurred.
","parent_name":"InvalidDataError"},"Enums/InvalidDataError.html#/s:6Health16InvalidDataErrorO13serializationACSScACmF":{"name":"serialization","abstract":"A serialization error occurred.
","parent_name":"InvalidDataError"},"Enums/InvalidDataError.html":{"name":"InvalidDataError","abstract":"InvalidDataError enum
"},"Enums/State.html":{"name":"State","abstract":"State enum
"},"Classes/StatusDateFormatter.html#/s:6Health19StatusDateFormatterC6stringSS10Foundation0C0V4from_tF":{"name":"string(from:)","abstract":"Returns a timestamp string representation from the Date parameter.
","parent_name":"StatusDateFormatter"},"Classes/StatusDateFormatter.html#/s:6Health19StatusDateFormatterC4date10Foundation0C0VSgSS4from_tF":{"name":"date(from:)","abstract":"Returns a Date instance that corresponds to the string parameter.
","parent_name":"StatusDateFormatter"},"Classes/Health.html#/s:6HealthAAC6statusAA6StatusVvp":{"name":"status","abstract":"Status instance variable.
","parent_name":"Health"},"Classes/Health.html#/s:6HealthAAC14numberOfChecksSivp":{"name":"numberOfChecks","abstract":"Number of health checks registered.
","parent_name":"Health"},"Classes/Health.html#/s:6HealthAACABSi20statusExpirationTime_tcfc":{"name":"init(statusExpirationTime:)","abstract":"Creates an instance of the Health class.
","parent_name":"Health"},"Classes/Health.html#/s:6HealthAAC8addCheckyAA0aC0_p5check_tF":{"name":"addCheck(check:)","abstract":"Registers a health check.
","parent_name":"Health"},"Classes/Health.html#/s:6HealthAAC8addCheckyAA5StateOyc5check_tF":{"name":"addCheck(check:)","abstract":"Registers a health check.
","parent_name":"Health"},"Classes/Health.html#/s:6HealthAAC17forceUpdateStatusyyF":{"name":"forceUpdateStatus()","abstract":"Forces an update to the status of this instance.
","parent_name":"Health"},"Classes/Health.html":{"name":"Health","abstract":"The Health class provides a concrete implementation of the HealthProtocol protocol that"},"Classes/StatusDateFormatter.html":{"name":"StatusDateFormatter","abstract":"
Struct that encapsulates a DateFormatter implementation, specifically used by the Status struct.
"},"Classes.html":{"name":"Classes","abstract":"The following classes are available globally.
"},"Enums.html":{"name":"Enumerations","abstract":"The following enumerations are available globally.
"},"Extensions.html":{"name":"Extensions","abstract":"The following extensions are available globally.
"},"Protocols.html":{"name":"Protocols","abstract":"The following protocols are available globally.
"},"Structs.html":{"name":"Structures","abstract":"The following structures are available globally.
"},"Typealiases.html":{"name":"Type Aliases","abstract":"The following type aliases are available globally.
"}}
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/search.json:
--------------------------------------------------------------------------------
1 | {"Typealiases.html#/s:6Health0A12CheckClosurea":{"name":"HealthCheckClosure","abstract":"HealthCheckClosure is a type alias for a closure that receives no arguments and"},"Structs/Status.html#/s:6Health6StatusV13dateFormatterAA0b4DateD0CvpZ":{"name":"dateFormatter","abstract":"
The date formatter used by the Status struct.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV10dateFormatSSvpZ":{"name":"dateFormat","abstract":"The date format used by the timestamp value in the dictionary.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV5stateAA5StateOvp":{"name":"state","abstract":"The state value contained within this struct.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV7detailsSaySSGvp":{"name":"details","abstract":"List of details describing any failures.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV10tsInMilliss6UInt64Vvp":{"name":"tsInMillis","abstract":"The timestamp value in milliseconds for the status.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV9timestampSSvp":{"name":"timestamp","abstract":"The string timestamp value for the status.
","parent_name":"Status"},"Structs/Status.html#/s:s9EquatableP2eeoiSbx_xtFZ":{"name":"==(_:_:)","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusVAcA5StateO5state_SaySSG7detailsSS9timestamptcfc":{"name":"init(state:details:timestamp:)","abstract":"Initializes the Status struct, which encapsulates the status of an application.
","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV12toDictionarys0D0VySSypGyF":{"name":"toDictionary()","abstract":"Returns a dictionary that contains the current status information. This dictionary","parent_name":"Status"},"Structs/Status.html#/s:6Health6StatusV18toSimpleDictionarys0E0VySSypGyF":{"name":"toSimpleDictionary()","abstract":"
Returns a simple dictionary that contains the current status information. This dictionary","parent_name":"Status"},"Structs/Status.html#/s:s9EncodableP6encodeys7Encoder_p2to_tKF":{"name":"encode(to:)","parent_name":"Status"},"Structs/Status.html#/s:s9DecodablePxs7Decoder_p4from_tKcfc":{"name":"init(from:)","parent_name":"Status"},"Structs/Status.html":{"name":"Status","abstract":"
Struct that encapsulates the status of an application.
"},"Protocols/HealthProtocol.html#/s:6Health0A8ProtocolP6statusAA6StatusVvp":{"name":"status","abstract":"Status instance variable.
","parent_name":"HealthProtocol"},"Protocols/HealthProtocol.html#/s:6Health0A8ProtocolP8addCheckyAA0aD0_p5check_tF":{"name":"addCheck(check:)","abstract":"Registers a health check.
","parent_name":"HealthProtocol"},"Protocols/HealthProtocol.html#/s:6Health0A8ProtocolP8addCheckyAA5StateOyc5check_tF":{"name":"addCheck(check:)","abstract":"Registers a health check.
","parent_name":"HealthProtocol"},"Protocols/HealthCheck.html#/s:6Health0A5CheckP4nameSSvp":{"name":"name","abstract":"Name for the health check.
","parent_name":"HealthCheck"},"Protocols/HealthCheck.html#/s:6Health0A5CheckP11descriptionSSvp":{"name":"description","abstract":"Description for the health check.
","parent_name":"HealthCheck"},"Protocols/HealthCheck.html#/s:6Health0A5CheckP8evaluateAA5StateOyF":{"name":"evaluate()","abstract":"Performs the health check test.
","parent_name":"HealthCheck"},"Protocols/HealthCheck.html":{"name":"HealthCheck","abstract":"Health check classes should extend this protocol to provide concrete implementations.
"},"Protocols/HealthProtocol.html":{"name":"HealthProtocol","abstract":"Specifies the blueprint that must be implemented to satisfy the needs of a Health class."},"Extensions/Date.html#/s:10Foundation4DateV6HealthE17currentTimeMilliss6UInt64VyFZ":{"name":"currentTimeMillis()","abstract":"
Returns the current time in milliseconds.
","parent_name":"Date"},"Extensions/Date.html#/s:10Foundation4DateV6HealthEACs6UInt64V12timeInMillis_tcfc":{"name":"init(timeInMillis:)","abstract":"Creates a Date instance from milliseconds.
","parent_name":"Date"},"Extensions/Date.html":{"name":"Date","abstract":"Extension to the Date type.
"},"Enums/State.html#/s:6Health5StateO2UPA2CmF":{"name":"UP","abstract":"Application is running just fine.
","parent_name":"State"},"Enums/State.html#/s:6Health5StateO4DOWNA2CmF":{"name":"DOWN","abstract":"Application health is not good.
","parent_name":"State"},"Enums/InvalidDataError.html#/s:6Health16InvalidDataErrorO15deserializationACSScACmF":{"name":"deserialization","abstract":"A deserialization error occurred.
","parent_name":"InvalidDataError"},"Enums/InvalidDataError.html#/s:6Health16InvalidDataErrorO13serializationACSScACmF":{"name":"serialization","abstract":"A serialization error occurred.
","parent_name":"InvalidDataError"},"Enums/InvalidDataError.html":{"name":"InvalidDataError","abstract":"InvalidDataError enum
"},"Enums/State.html":{"name":"State","abstract":"State enum
"},"Classes/StatusDateFormatter.html#/s:6Health19StatusDateFormatterC6stringSS10Foundation0C0V4from_tF":{"name":"string(from:)","abstract":"Returns a timestamp string representation from the Date parameter.
","parent_name":"StatusDateFormatter"},"Classes/StatusDateFormatter.html#/s:6Health19StatusDateFormatterC4date10Foundation0C0VSgSS4from_tF":{"name":"date(from:)","abstract":"Returns a Date instance that corresponds to the string parameter.
","parent_name":"StatusDateFormatter"},"Classes/Health.html#/s:6HealthAAC6statusAA6StatusVvp":{"name":"status","abstract":"Status instance variable.
","parent_name":"Health"},"Classes/Health.html#/s:6HealthAAC14numberOfChecksSivp":{"name":"numberOfChecks","abstract":"Number of health checks registered.
","parent_name":"Health"},"Classes/Health.html#/s:6HealthAACABSi20statusExpirationTime_tcfc":{"name":"init(statusExpirationTime:)","abstract":"Creates an instance of the Health class.
","parent_name":"Health"},"Classes/Health.html#/s:6HealthAAC8addCheckyAA0aC0_p5check_tF":{"name":"addCheck(check:)","abstract":"Registers a health check.
","parent_name":"Health"},"Classes/Health.html#/s:6HealthAAC8addCheckyAA5StateOyc5check_tF":{"name":"addCheck(check:)","abstract":"Registers a health check.
","parent_name":"Health"},"Classes/Health.html#/s:6HealthAAC17forceUpdateStatusyyF":{"name":"forceUpdateStatus()","abstract":"Forces an update to the status of this instance.
","parent_name":"Health"},"Classes/Health.html":{"name":"Health","abstract":"The Health class provides a concrete implementation of the HealthProtocol protocol that"},"Classes/StatusDateFormatter.html":{"name":"StatusDateFormatter","abstract":"
Struct that encapsulates a DateFormatter implementation, specifically used by the Status struct.
"},"Classes.html":{"name":"Classes","abstract":"The following classes are available globally.
"},"Enums.html":{"name":"Enumerations","abstract":"The following enumerations are available globally.
"},"Extensions.html":{"name":"Extensions","abstract":"The following extensions are available globally.
"},"Protocols.html":{"name":"Protocols","abstract":"The following protocols are available globally.
"},"Structs.html":{"name":"Structures","abstract":"The following structures are available globally.
"},"Typealiases.html":{"name":"Type Aliases","abstract":"The following type aliases are available globally.
"}}
--------------------------------------------------------------------------------
/Tests/HealthTests/HealthTests.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright IBM Corporation 2017
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | import XCTest
18 | import Foundation
19 |
20 | @testable import Health
21 |
22 | class HealthTests: XCTestCase {
23 |
24 | static var allTests: [(String, (HealthTests) -> () throws -> Void)] {
25 | return [
26 | ("testBasicConstruction", testBasicConstruction),
27 | ("testAddChecks", testAddChecks),
28 | ("testStatusSerialization", testStatusSerialization),
29 | ("testDateExtensions", testDateExtensions),
30 | ("testDateFormatter", testDateFormatter)
31 | ]
32 | }
33 |
34 | class MyPositiveCheck: HealthCheck {
35 | public var name: String { get { return "MyPositiveCheck"} }
36 | public var description: String { get { return "Description for MyPositiveCheck..."} }
37 | public func evaluate() -> State {
38 | return State.UP
39 | }
40 | }
41 |
42 | class MyNegativeCheck: HealthCheck {
43 | public var name: String { get { return "MyNegativeCheck"} }
44 | public var description: String { get { return "Description for MyNegativeCheck..."} }
45 | public func evaluate() -> State {
46 | return State.DOWN
47 | }
48 | }
49 |
50 | func myPositiveClosureCheck() -> State {
51 | return State.UP
52 | }
53 |
54 | func myNegativeClosureCheck() -> State {
55 | return State.DOWN
56 | }
57 |
58 | override func setUp() {
59 | super.setUp()
60 | }
61 |
62 | // Create Stats, and check that default values are set
63 | func testBasicConstruction() {
64 |
65 | // Create Health instance
66 | let health = Health()
67 |
68 | // Assert initial state
69 | XCTAssertEqual(health.numberOfChecks, 0)
70 | XCTAssertEqual(health.status.state, State.UP)
71 | XCTAssertEqual(health.status.details.count, 0)
72 |
73 | // Assert contents of simple dictionary
74 | let simpleDictionary = health.status.toSimpleDictionary()
75 | print("simpleDictionary: \(simpleDictionary)")
76 | XCTAssertEqual(simpleDictionary.count, 1)
77 | let simpleKeys = simpleDictionary.keys
78 | XCTAssertTrue(simpleKeys.contains("status"))
79 | if let status = simpleDictionary["status"] as? String {
80 | XCTAssertEqual(status, "UP")
81 | } else {
82 | XCTFail("Non-expected status in dictionary.")
83 | }
84 |
85 | // Assert contents of dictionary
86 | let dictionary = health.status.toDictionary()
87 | print("dictionary: \(dictionary)")
88 | // There should only be two keys
89 | XCTAssertEqual(dictionary.count, 3)
90 | let keys = dictionary.keys
91 | XCTAssertTrue(keys.contains("status"))
92 | XCTAssertTrue(keys.contains("details"))
93 | XCTAssertTrue(keys.contains("timestamp"))
94 |
95 | // Validate status
96 | if let status = dictionary["status"] as? String {
97 | XCTAssertEqual(status, "UP")
98 | } else {
99 | XCTFail("'status' field missing in dictionary.")
100 | }
101 |
102 | // Validate details
103 | if let details = dictionary["details"] as? [String] {
104 | XCTAssertEqual(details.count, 0)
105 | } else {
106 | XCTFail("'details' field missing in dictionary.")
107 | }
108 |
109 | // Validate timestamp
110 | if let timestamp = dictionary["timestamp"] as? String {
111 | let dateFormatter = DateFormatter()
112 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
113 | let date = dateFormatter.date(from: timestamp)
114 | XCTAssertNotNil(date, "'timestamp' field in dictionary does not match expected format.")
115 | } else {
116 | XCTFail("'timestamp' field missing in dictionary.")
117 | }
118 | }
119 |
120 | func testAddChecks() {
121 | // Create Health instance
122 | let statusExpirationTime = 3000
123 | let health = Health(statusExpirationTime: statusExpirationTime)
124 |
125 | // Add checks
126 | health.addCheck(check: MyPositiveCheck())
127 | health.addCheck(check: MyNegativeCheck())
128 | health.addCheck(check: myPositiveClosureCheck)
129 | health.addCheck(check: myNegativeClosureCheck)
130 |
131 | // Perform assertions
132 | XCTAssertEqual(health.numberOfChecks, 4)
133 | // State should still be up (caching - 30 seconds)
134 | XCTAssertEqual(health.status.state, State.UP)
135 | // Wait for cache to expire
136 | sleep(UInt32((statusExpirationTime + 1000)/1000))
137 | // State should be down now...
138 | XCTAssertEqual(health.status.state, State.DOWN)
139 |
140 | // Assert contents of dictionary
141 | let dictionary = health.status.toDictionary()
142 | print("dictionary: \(dictionary)")
143 | if let status = dictionary["status"] as? String {
144 | XCTAssertEqual(status, "DOWN")
145 | } else {
146 | XCTFail("Non-expected status in dictionary.")
147 | }
148 |
149 | if let details = dictionary["details"] as? [String] {
150 | //print("details: \(details)")
151 | XCTAssertEqual(details.count, 2)
152 | XCTAssertTrue(details.contains("Description for MyNegativeCheck..."))
153 | XCTAssertTrue(details.contains("A health check closure reported status as DOWN."))
154 | } else {
155 | XCTFail("Non-expected details in dictionary.")
156 | }
157 | }
158 |
159 | func testDateFormatter() {
160 | // Validate conversion from string timestamp to date and back to string timestamp
161 | let dateStr1 = "2017-10-31T16:15:56+0000"
162 | let dateFormatter = StatusDateFormatter()
163 | guard let date1 = dateFormatter.date(from: dateStr1) else {
164 | XCTFail("Failed to compute date from valid string timestamp!")
165 | return
166 | }
167 | let computedDateStr1 = dateFormatter.string(from: date1)
168 | XCTAssertEqual(dateStr1, computedDateStr1, "Timestamp string values did not match!")
169 |
170 | // Validate conversion to string timestamp from milliseconds
171 | let milliseconds: UInt64 = 1509466556000
172 | let date2 = Date(timeInMillis: milliseconds)
173 | let dateStr2 = dateFormatter.string(from: date2)
174 | XCTAssertEqual(dateStr2, "2017-10-31T16:15:56+0000", "Timestamp string values did not match!")
175 | }
176 |
177 | func testDateExtensions() {
178 | // Compare millis
179 | let milliseconds: UInt64 = 1509466556000
180 | let date1 = Date(timeIntervalSince1970: TimeInterval(milliseconds / 1000))
181 | let date2 = Date(timeInMillis: milliseconds)
182 | XCTAssertEqual(date1.timeIntervalSince1970, date2.timeIntervalSince1970, "timeIntervalSince1970 values did not match!")
183 | XCTAssertEqual(date1.milliseconds, milliseconds, "milliseconds values did not match!")
184 | XCTAssertEqual(date2.milliseconds, milliseconds, "milliseconds values did not match!")
185 | }
186 |
187 | func testStatusSerialization() {
188 | // Validate serialization and deserialization of status instance
189 | let status: Status = Status(state: .DOWN, details: ["details1", "details2", "details3"], timestamp: "2017-10-31T16:15:56+0000")
190 |
191 | guard let data = try? JSONEncoder().encode(status) else {
192 | XCTFail("Failed to encode Status instance!")
193 | return
194 | }
195 |
196 | guard let decodedStatus = try? JSONDecoder().decode(Status.self, from: data) else {
197 | XCTFail("Failed to decode JSON data into a Status instance!")
198 | return
199 | }
200 |
201 | XCTAssertEqual(status, decodedStatus, "Failed to encode and decode Status instance!")
202 | }
203 |
204 | }
205 |
--------------------------------------------------------------------------------
/docs/Enums.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Enumerations Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | Health Reference
45 |
46 | Enumerations Reference
47 |
48 |
49 |
50 |
51 |
110 |
111 |
112 |
113 |
114 |
115 |
Enumerations
116 |
The following enumerations are available globally.
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
133 |
134 |
135 |
136 |
137 |
138 |
InvalidDataError enum
139 |
140 |
Enumeration that represents data errors.
141 |
142 |
See more
143 |
144 |
145 |
Declaration
146 |
147 |
Swift
148 |
public enum InvalidDataError : Error
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 | State
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
State enum
169 |
170 |
Enumeration that encapsulates the two possible states for an application, UP or DOWN.
171 |
172 |
See more
173 |
174 |
175 |
Declaration
176 |
177 |
Swift
178 |
public enum State : String
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
196 |
197 |
198 |
199 |
--------------------------------------------------------------------------------
/docs/Protocols.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Protocols Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | Health Reference
45 |
46 | Protocols Reference
47 |
48 |
49 |
50 |
51 |
110 |
111 |
112 |
113 |
114 |
115 |
Protocols
116 |
The following protocols are available globally.
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
133 |
134 |
135 |
136 |
137 |
138 |
Health check classes should extend this protocol to provide concrete implementations.
139 |
140 |
See more
141 |
142 |
143 |
Declaration
144 |
145 |
Swift
146 |
public protocol HealthCheck
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
161 |
162 |
163 |
164 |
165 |
166 |
Specifies the blueprint that must be implemented to satisfy the needs of a Health class.
167 | A concrete implementation of this protocol is already provided by this library (Health).
168 |
169 |
See more
170 |
171 |
172 |
Declaration
173 |
174 |
Swift
175 |
public protocol HealthProtocol
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
193 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/Enums.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Enumerations Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | Health Reference
45 |
46 | Enumerations Reference
47 |
48 |
49 |
50 |
51 |
110 |
111 |
112 |
113 |
114 |
115 |
Enumerations
116 |
The following enumerations are available globally.
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
133 |
134 |
135 |
136 |
137 |
138 |
InvalidDataError enum
139 |
140 |
Enumeration that represents data errors.
141 |
142 |
See more
143 |
144 |
145 |
Declaration
146 |
147 |
Swift
148 |
public enum InvalidDataError : Error
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 | State
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
State enum
169 |
170 |
Enumeration that encapsulates the two possible states for an application, UP or DOWN.
171 |
172 |
See more
173 |
174 |
175 |
Declaration
176 |
177 |
Swift
178 |
public enum State : String
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
196 |
197 |
198 |
199 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/Protocols.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Protocols Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
42 |
43 |
44 | Health Reference
45 |
46 | Protocols Reference
47 |
48 |
49 |
50 |
51 |
110 |
111 |
112 |
113 |
114 |
115 |
Protocols
116 |
The following protocols are available globally.
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
133 |
134 |
135 |
136 |
137 |
138 |
Health check classes should extend this protocol to provide concrete implementations.
139 |
140 |
See more
141 |
142 |
143 |
Declaration
144 |
145 |
Swift
146 |
public protocol HealthCheck
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
161 |
162 |
163 |
164 |
165 |
166 |
Specifies the blueprint that must be implemented to satisfy the needs of a Health class.
167 | A concrete implementation of this protocol is already provided by this library (Health).
168 |
169 |
See more
170 |
171 |
172 |
Declaration
173 |
174 |
Swift
175 |
public protocol HealthProtocol
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
193 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/Sources/Health/Protocols.swift:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright IBM Corporation 2017
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | **/
16 |
17 | import Foundation
18 | import LoggerAPI
19 |
20 | /// InvalidDataError enum
21 | ///
22 | /// Enumeration that represents data errors.
23 | public enum InvalidDataError: Error {
24 |
25 | /// A deserialization error occurred.
26 | case deserialization(String)
27 |
28 | /// A serialization error occurred.
29 | case serialization(String)
30 | }
31 |
32 | /// State enum
33 | ///
34 | /// Enumeration that encapsulates the two possible states for an application, UP or DOWN.
35 | public enum State: String {
36 |
37 | /// Application is running just fine.
38 | case UP
39 | /// Application health is not good.
40 | case DOWN
41 | }
42 |
43 | /// Struct that encapsulates a `DateFormatter` implementation, specifically used by the Status struct.
44 | public class StatusDateFormatter {
45 | private let dateFormatter: DateFormatter
46 |
47 | /// Constructor
48 | ///
49 | /// Wraps a `DateFormatter` instance, sets its timezone to UTC and its date format to 'yyyy-MM-dd'T'HH:mm:ssZ'.
50 | init() {
51 | self.dateFormatter = DateFormatter()
52 | self.dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
53 | if let timeZone = TimeZone(identifier: "UTC") {
54 | self.dateFormatter.timeZone = timeZone
55 | } else {
56 | // This should never occur...
57 | Log.warning("UTC time zone not found.")
58 | }
59 | }
60 |
61 | /// Returns a timestamp string representation from the `Date` parameter.
62 | /// - Parameter from: A Date instance to obtain the date value from.
63 | public func string(from date: Date) -> String {
64 | return dateFormatter.string(from: date)
65 | }
66 |
67 | /// Returns a `Date` instance that corresponds to the string parameter.
68 | /// - Parameter from: A string in the "yyyy-MM-dd'T'HH:mm:ssZ" format.
69 | public func date(from string: String) -> Date? {
70 | return dateFormatter.date(from: string)
71 | }
72 |
73 | var dateFormat: String {
74 | get {
75 | return self.dateFormatter.dateFormat
76 | }
77 | }
78 | }
79 |
80 | /// Struct that encapsulates the status of an application.
81 | public struct Status: Equatable {
82 | /// The date formatter used by the `Status` struct.
83 | public static let dateFormatter = StatusDateFormatter()
84 |
85 | /// The date format used by the timestamp value in the dictionary.
86 | public static var dateFormat: String {
87 | get {
88 | return dateFormatter.dateFormat
89 | }
90 | }
91 |
92 | /// The state value contained within this struct.
93 | public let state: State
94 | /// List of details describing any failures.
95 | public let details: [String]
96 | /// The timestamp value in milliseconds for the status.
97 | public var tsInMillis: UInt64 {
98 | get {
99 | let date = Status.dateFormatter.date(from: timestamp)
100 | return date!.milliseconds
101 | }
102 | }
103 | /// The string timestamp value for the status.
104 | public let timestamp: String
105 |
106 | enum CodingKeys: String, CodingKey {
107 | case status
108 | case details
109 | case timestamp
110 | }
111 |
112 | public static func ==(lhs: Status, rhs: Status) -> Bool {
113 | return (lhs.state == rhs.state) && (lhs.details == rhs.details) && (lhs.timestamp == rhs.timestamp)
114 | }
115 |
116 | /// Initializes the `Status` struct, which encapsulates the status of an application.
117 | ///
118 | /// - Parameter state: Optional. The state value for this Status instance (default value is 'UP').
119 | /// - Parameter details: Optional. A list of strings that describes any issues that may have
120 | /// occurred while executing a health check.
121 | /// - Parameter timestamp: Optional. The string timestamp value for the status (default value is current time).
122 | public init(state: State = State.UP, details: [String] = [], timestamp: String = dateFormatter.string(from: Date())) {
123 | self.state = state
124 | self.details = details
125 | if let _ = Status.dateFormatter.date(from: timestamp) {
126 | self.timestamp = timestamp
127 | } else {
128 | self.timestamp = Status.dateFormatter.string(from: Date())
129 | Log.warning("Provided timestamp value '\(timestamp)' is not valid; using current time value instead.")
130 | }
131 | }
132 |
133 | /// Returns a dictionary that contains the current status information. This dictionary
134 | /// contains three key-pair values, where the keys are 'status', 'timestamp', and 'details'.
135 | public func toDictionary() -> [String : Any] {
136 | // Transform time in milliseconds to readable format
137 | //let timestamp = Status.dateFormatter.string(from: Date(timeInMillis: self.tsInMillis))
138 | // Add state & details to dictionary
139 | let dict = ["status" : self.state.rawValue, "details" : details, "timestamp" : timestamp] as [String : Any]
140 | return dict
141 | }
142 |
143 | /// Returns a simple dictionary that contains the current status information. This dictionary
144 | /// contains one key-pair value, where the key is 'status' and the value is either 'UP' or 'DOWN'.
145 | public func toSimpleDictionary() -> [String : Any] {
146 | // Add state & details to dictionary
147 | let dict = ["status" : self.state.rawValue] as [String : Any]
148 | return dict
149 | }
150 | }
151 |
152 | /// Extension for the `Status` struct that conforms to the Encodable protocol.
153 | extension Status: Encodable {
154 | public func encode(to encoder: Encoder) throws {
155 | var container = encoder.container(keyedBy: CodingKeys.self)
156 | try container.encode(self.state.rawValue, forKey: .status)
157 | try container.encode(self.details, forKey: .details)
158 | try container.encode(self.timestamp, forKey: .timestamp)
159 | }
160 | }
161 |
162 | /// Extension for the `Status` struct that conforms to the Decodable protocol.
163 | extension Status: Decodable {
164 | public init(from decoder: Decoder) throws {
165 | let values = try decoder.container(keyedBy: CodingKeys.self)
166 | var status = try values.decode(String.self, forKey: .status)
167 |
168 | if status == "" {
169 | status = "DOWN"
170 | }
171 |
172 | guard let state = State(rawValue: status) else {
173 | throw InvalidDataError.deserialization("'\(status)' is not a valid status value.")
174 | }
175 |
176 | let details = try values.decode([String].self, forKey: .details)
177 | var timestamp = try values.decode(String.self, forKey: .timestamp)
178 |
179 | if timestamp == "" {
180 | let dateFormatter = DateFormatter()
181 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
182 | let date = Date()
183 | timestamp = dateFormatter.string(from: date)
184 | }
185 |
186 | guard let _ = Status.dateFormatter.date(from: timestamp) else {
187 | throw InvalidDataError.deserialization("'\(timestamp)' is not a valid timestamp value.")
188 | }
189 |
190 | self.init(state: state, details: details, timestamp: timestamp)
191 | }
192 | }
193 |
194 | /// HealthCheckClosure is a type alias for a closure that receives no arguments and
195 | /// returns a State value.
196 | public typealias HealthCheckClosure = () -> State
197 |
198 | /// Health check classes should extend this protocol to provide concrete implementations.
199 | public protocol HealthCheck {
200 | /// Name for the health check.
201 | var name: String { get }
202 | /// Description for the health check.
203 | var description: String { get }
204 | /// Performs the health check test.
205 | func evaluate() -> State
206 | }
207 |
208 | /// Specifies the blueprint that must be implemented to satisfy the needs of a `Health` class.
209 | /// A concrete implementation of this protocol is already provided by this library (Health).
210 | public protocol HealthProtocol {
211 | /// Status instance variable.
212 | var status: Status { get }
213 | /// Registers a health check.
214 | ///
215 | /// - Parameter check: An object that extends the `HealthCheck` class.
216 | func addCheck(check: HealthCheck)
217 | /// Registers a health check.
218 | ///
219 | /// - Parameter check: A closure that conforms to the `HealthCheckClosure` type alias.
220 | func addCheck(check: @escaping HealthCheckClosure)
221 | }
222 |
--------------------------------------------------------------------------------
/docs/Enums/State.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | State Enumeration Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | Health Reference
46 |
47 | State Enumeration Reference
48 |
49 |
50 |
51 |
52 |
111 |
112 |
113 |
114 |
115 |
116 |
State
117 |
118 |
119 |
public enum State : String
120 |
121 |
122 |
123 |
State enum
124 |
125 |
Enumeration that encapsulates the two possible states for an application, UP or DOWN.
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | UP
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
Application is running just fine.
148 |
149 |
150 |
151 |
Declaration
152 |
153 |
Swift
154 |
case UP
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | DOWN
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
Application health is not good.
179 |
180 |
181 |
182 |
Declaration
183 |
184 |
Swift
185 |
case DOWN
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
203 |
204 |
205 |
206 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/Enums/State.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | State Enumeration Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | Health Reference
46 |
47 | State Enumeration Reference
48 |
49 |
50 |
51 |
52 |
111 |
112 |
113 |
114 |
115 |
116 |
State
117 |
118 |
119 |
public enum State : String
120 |
121 |
122 |
123 |
State enum
124 |
125 |
Enumeration that encapsulates the two possible states for an application, UP or DOWN.
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 | UP
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
Application is running just fine.
148 |
149 |
150 |
151 |
Declaration
152 |
153 |
Swift
154 |
case UP
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | DOWN
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
Application health is not good.
179 |
180 |
181 |
182 |
Declaration
183 |
184 |
Swift
185 |
case DOWN
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
203 |
204 |
205 |
206 |
--------------------------------------------------------------------------------
/docs/css/jazzy.css:
--------------------------------------------------------------------------------
1 | *, *:before, *:after {
2 | box-sizing: inherit; }
3 |
4 | body {
5 | margin: 0;
6 | background: #fff;
7 | color: #333;
8 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
9 | letter-spacing: .2px;
10 | -webkit-font-smoothing: antialiased;
11 | box-sizing: border-box; }
12 |
13 | h1 {
14 | font-size: 2rem;
15 | font-weight: 700;
16 | margin: 1.275em 0 0.6em; }
17 |
18 | h2 {
19 | font-size: 1.75rem;
20 | font-weight: 700;
21 | margin: 1.275em 0 0.3em; }
22 |
23 | h3 {
24 | font-size: 1.5rem;
25 | font-weight: 700;
26 | margin: 1em 0 0.3em; }
27 |
28 | h4 {
29 | font-size: 1.25rem;
30 | font-weight: 700;
31 | margin: 1.275em 0 0.85em; }
32 |
33 | h5 {
34 | font-size: 1rem;
35 | font-weight: 700;
36 | margin: 1.275em 0 0.85em; }
37 |
38 | h6 {
39 | font-size: 1rem;
40 | font-weight: 700;
41 | margin: 1.275em 0 0.85em;
42 | color: #777; }
43 |
44 | p {
45 | margin: 0 0 1em; }
46 |
47 | ul, ol {
48 | padding: 0 0 0 2em;
49 | margin: 0 0 0.85em; }
50 |
51 | blockquote {
52 | margin: 0 0 0.85em;
53 | padding: 0 15px;
54 | color: #858585;
55 | border-left: 4px solid #e5e5e5; }
56 |
57 | img {
58 | max-width: 100%; }
59 |
60 | a {
61 | color: #4183c4;
62 | text-decoration: none; }
63 | a:hover, a:focus {
64 | outline: 0;
65 | text-decoration: underline; }
66 |
67 | table {
68 | background: #fff;
69 | width: 100%;
70 | border-collapse: collapse;
71 | border-spacing: 0;
72 | overflow: auto;
73 | margin: 0 0 0.85em; }
74 |
75 | tr:nth-child(2n) {
76 | background-color: #fbfbfb; }
77 |
78 | th, td {
79 | padding: 6px 13px;
80 | border: 1px solid #ddd; }
81 |
82 | pre {
83 | margin: 0 0 1.275em;
84 | padding: .85em 1em;
85 | overflow: auto;
86 | background: #f7f7f7;
87 | font-size: .85em;
88 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; }
89 |
90 | code {
91 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; }
92 |
93 | p > code, li > code {
94 | background: #f7f7f7;
95 | padding: .2em; }
96 | p > code:before, p > code:after, li > code:before, li > code:after {
97 | letter-spacing: -.2em;
98 | content: "\00a0"; }
99 |
100 | pre code {
101 | padding: 0;
102 | white-space: pre; }
103 |
104 | .content-wrapper {
105 | display: flex;
106 | flex-direction: column; }
107 | @media (min-width: 768px) {
108 | .content-wrapper {
109 | flex-direction: row; } }
110 |
111 | .header {
112 | display: flex;
113 | padding: 8px;
114 | font-size: 0.875em;
115 | background: #444;
116 | color: #999; }
117 |
118 | .header-col {
119 | margin: 0;
120 | padding: 0 8px; }
121 |
122 | .header-col--primary {
123 | flex: 1; }
124 |
125 | .header-link {
126 | color: #fff; }
127 |
128 | .header-icon {
129 | padding-right: 6px;
130 | vertical-align: -4px;
131 | height: 16px; }
132 |
133 | .breadcrumbs {
134 | font-size: 0.875em;
135 | padding: 8px 16px;
136 | margin: 0;
137 | background: #fbfbfb;
138 | border-bottom: 1px solid #ddd; }
139 |
140 | .carat {
141 | height: 10px;
142 | margin: 0 5px; }
143 |
144 | .navigation {
145 | order: 2; }
146 | @media (min-width: 768px) {
147 | .navigation {
148 | order: 1;
149 | width: 25%;
150 | max-width: 300px;
151 | padding-bottom: 64px;
152 | overflow: hidden;
153 | word-wrap: normal;
154 | background: #fbfbfb;
155 | border-right: 1px solid #ddd; } }
156 |
157 | .nav-groups {
158 | list-style-type: none;
159 | padding-left: 0; }
160 |
161 | .nav-group-name {
162 | border-bottom: 1px solid #ddd;
163 | padding: 8px 0 8px 16px; }
164 |
165 | .nav-group-name-link {
166 | color: #333; }
167 |
168 | .nav-group-tasks {
169 | margin: 8px 0;
170 | padding: 0 0 0 8px; }
171 |
172 | .nav-group-task {
173 | font-size: 1em;
174 | list-style-type: none;
175 | white-space: nowrap; }
176 |
177 | .nav-group-task-link {
178 | color: #808080; }
179 |
180 | .main-content {
181 | order: 1; }
182 | @media (min-width: 768px) {
183 | .main-content {
184 | order: 2;
185 | flex: 1;
186 | padding-bottom: 60px; } }
187 |
188 | .section {
189 | padding: 0 32px;
190 | border-bottom: 1px solid #ddd; }
191 |
192 | .section-content {
193 | max-width: 834px;
194 | margin: 0 auto;
195 | padding: 16px 0; }
196 |
197 | .section-name {
198 | color: #666;
199 | display: block; }
200 |
201 | .declaration .highlight {
202 | overflow-x: initial;
203 | padding: 8px 0;
204 | margin: 0;
205 | background-color: transparent;
206 | border: none; }
207 |
208 | .task-group-section {
209 | border-top: 1px solid #ddd; }
210 |
211 | .task-group {
212 | padding-top: 0px; }
213 |
214 | .task-name-container a[name]:before {
215 | content: "";
216 | display: block; }
217 |
218 | .item-container {
219 | padding: 0; }
220 |
221 | .item {
222 | padding-top: 8px;
223 | width: 100%;
224 | list-style-type: none; }
225 | .item a[name]:before {
226 | content: "";
227 | display: block; }
228 | .item .token {
229 | padding-left: 3px;
230 | margin-left: 0px;
231 | font-size: 1rem; }
232 | .item .declaration-note {
233 | font-size: .85em;
234 | color: #808080;
235 | font-style: italic; }
236 |
237 | .pointer-container {
238 | border-bottom: 1px solid #ddd;
239 | left: -23px;
240 | padding-bottom: 13px;
241 | position: relative;
242 | width: 110%; }
243 |
244 | .pointer {
245 | left: 21px;
246 | top: 7px;
247 | display: block;
248 | position: absolute;
249 | width: 12px;
250 | height: 12px;
251 | border-left: 1px solid #ddd;
252 | border-top: 1px solid #ddd;
253 | background: #fff;
254 | transform: rotate(45deg); }
255 |
256 | .height-container {
257 | display: none;
258 | position: relative;
259 | width: 100%;
260 | overflow: hidden; }
261 | .height-container .section {
262 | background: #fff;
263 | border: 1px solid #ddd;
264 | border-top-width: 0;
265 | padding-top: 10px;
266 | padding-bottom: 5px;
267 | padding: 8px 16px; }
268 |
269 | .aside, .language {
270 | padding: 6px 12px;
271 | margin: 12px 0;
272 | border-left: 5px solid #dddddd;
273 | overflow-y: hidden; }
274 | .aside .aside-title, .language .aside-title {
275 | font-size: 9px;
276 | letter-spacing: 2px;
277 | text-transform: uppercase;
278 | padding-bottom: 0;
279 | margin: 0;
280 | color: #aaa;
281 | -webkit-user-select: none; }
282 | .aside p:last-child, .language p:last-child {
283 | margin-bottom: 0; }
284 |
285 | .language {
286 | border-left: 5px solid #cde9f4; }
287 | .language .aside-title {
288 | color: #4183c4; }
289 |
290 | .aside-warning {
291 | border-left: 5px solid #ff6666; }
292 | .aside-warning .aside-title {
293 | color: #ff0000; }
294 |
295 | .graybox {
296 | border-collapse: collapse;
297 | width: 100%; }
298 | .graybox p {
299 | margin: 0;
300 | word-break: break-word;
301 | min-width: 50px; }
302 | .graybox td {
303 | border: 1px solid #ddd;
304 | padding: 5px 25px 5px 10px;
305 | vertical-align: middle; }
306 | .graybox tr td:first-of-type {
307 | text-align: right;
308 | padding: 7px;
309 | vertical-align: top;
310 | word-break: normal;
311 | width: 40px; }
312 |
313 | .slightly-smaller {
314 | font-size: 0.9em; }
315 |
316 | .footer {
317 | padding: 8px 16px;
318 | background: #444;
319 | color: #ddd;
320 | font-size: 0.8em; }
321 | .footer p {
322 | margin: 8px 0; }
323 | .footer a {
324 | color: #fff; }
325 |
326 | html.dash .header, html.dash .breadcrumbs, html.dash .navigation {
327 | display: none; }
328 | html.dash .height-container {
329 | display: block; }
330 |
331 | form[role=search] input {
332 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
333 | font-size: 14px;
334 | line-height: 24px;
335 | padding: 0 10px;
336 | margin: 0;
337 | border: none;
338 | border-radius: 1em; }
339 | .loading form[role=search] input {
340 | background: white url(../img/spinner.gif) center right 4px no-repeat; }
341 | form[role=search] .tt-menu {
342 | margin: 0;
343 | min-width: 300px;
344 | background: #fbfbfb;
345 | color: #333;
346 | border: 1px solid #ddd; }
347 | form[role=search] .tt-highlight {
348 | font-weight: bold; }
349 | form[role=search] .tt-suggestion {
350 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
351 | padding: 0 8px; }
352 | form[role=search] .tt-suggestion span {
353 | display: table-cell;
354 | white-space: nowrap; }
355 | form[role=search] .tt-suggestion .doc-parent-name {
356 | width: 100%;
357 | text-align: right;
358 | font-weight: normal;
359 | font-size: 0.9em;
360 | padding-left: 16px; }
361 | form[role=search] .tt-suggestion:hover,
362 | form[role=search] .tt-suggestion.tt-cursor {
363 | cursor: pointer;
364 | background-color: #4183c4;
365 | color: #fff; }
366 | form[role=search] .tt-suggestion:hover .doc-parent-name,
367 | form[role=search] .tt-suggestion.tt-cursor .doc-parent-name {
368 | color: #fff; }
369 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/css/jazzy.css:
--------------------------------------------------------------------------------
1 | *, *:before, *:after {
2 | box-sizing: inherit; }
3 |
4 | body {
5 | margin: 0;
6 | background: #fff;
7 | color: #333;
8 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
9 | letter-spacing: .2px;
10 | -webkit-font-smoothing: antialiased;
11 | box-sizing: border-box; }
12 |
13 | h1 {
14 | font-size: 2rem;
15 | font-weight: 700;
16 | margin: 1.275em 0 0.6em; }
17 |
18 | h2 {
19 | font-size: 1.75rem;
20 | font-weight: 700;
21 | margin: 1.275em 0 0.3em; }
22 |
23 | h3 {
24 | font-size: 1.5rem;
25 | font-weight: 700;
26 | margin: 1em 0 0.3em; }
27 |
28 | h4 {
29 | font-size: 1.25rem;
30 | font-weight: 700;
31 | margin: 1.275em 0 0.85em; }
32 |
33 | h5 {
34 | font-size: 1rem;
35 | font-weight: 700;
36 | margin: 1.275em 0 0.85em; }
37 |
38 | h6 {
39 | font-size: 1rem;
40 | font-weight: 700;
41 | margin: 1.275em 0 0.85em;
42 | color: #777; }
43 |
44 | p {
45 | margin: 0 0 1em; }
46 |
47 | ul, ol {
48 | padding: 0 0 0 2em;
49 | margin: 0 0 0.85em; }
50 |
51 | blockquote {
52 | margin: 0 0 0.85em;
53 | padding: 0 15px;
54 | color: #858585;
55 | border-left: 4px solid #e5e5e5; }
56 |
57 | img {
58 | max-width: 100%; }
59 |
60 | a {
61 | color: #4183c4;
62 | text-decoration: none; }
63 | a:hover, a:focus {
64 | outline: 0;
65 | text-decoration: underline; }
66 |
67 | table {
68 | background: #fff;
69 | width: 100%;
70 | border-collapse: collapse;
71 | border-spacing: 0;
72 | overflow: auto;
73 | margin: 0 0 0.85em; }
74 |
75 | tr:nth-child(2n) {
76 | background-color: #fbfbfb; }
77 |
78 | th, td {
79 | padding: 6px 13px;
80 | border: 1px solid #ddd; }
81 |
82 | pre {
83 | margin: 0 0 1.275em;
84 | padding: .85em 1em;
85 | overflow: auto;
86 | background: #f7f7f7;
87 | font-size: .85em;
88 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; }
89 |
90 | code {
91 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; }
92 |
93 | p > code, li > code {
94 | background: #f7f7f7;
95 | padding: .2em; }
96 | p > code:before, p > code:after, li > code:before, li > code:after {
97 | letter-spacing: -.2em;
98 | content: "\00a0"; }
99 |
100 | pre code {
101 | padding: 0;
102 | white-space: pre; }
103 |
104 | .content-wrapper {
105 | display: flex;
106 | flex-direction: column; }
107 | @media (min-width: 768px) {
108 | .content-wrapper {
109 | flex-direction: row; } }
110 |
111 | .header {
112 | display: flex;
113 | padding: 8px;
114 | font-size: 0.875em;
115 | background: #444;
116 | color: #999; }
117 |
118 | .header-col {
119 | margin: 0;
120 | padding: 0 8px; }
121 |
122 | .header-col--primary {
123 | flex: 1; }
124 |
125 | .header-link {
126 | color: #fff; }
127 |
128 | .header-icon {
129 | padding-right: 6px;
130 | vertical-align: -4px;
131 | height: 16px; }
132 |
133 | .breadcrumbs {
134 | font-size: 0.875em;
135 | padding: 8px 16px;
136 | margin: 0;
137 | background: #fbfbfb;
138 | border-bottom: 1px solid #ddd; }
139 |
140 | .carat {
141 | height: 10px;
142 | margin: 0 5px; }
143 |
144 | .navigation {
145 | order: 2; }
146 | @media (min-width: 768px) {
147 | .navigation {
148 | order: 1;
149 | width: 25%;
150 | max-width: 300px;
151 | padding-bottom: 64px;
152 | overflow: hidden;
153 | word-wrap: normal;
154 | background: #fbfbfb;
155 | border-right: 1px solid #ddd; } }
156 |
157 | .nav-groups {
158 | list-style-type: none;
159 | padding-left: 0; }
160 |
161 | .nav-group-name {
162 | border-bottom: 1px solid #ddd;
163 | padding: 8px 0 8px 16px; }
164 |
165 | .nav-group-name-link {
166 | color: #333; }
167 |
168 | .nav-group-tasks {
169 | margin: 8px 0;
170 | padding: 0 0 0 8px; }
171 |
172 | .nav-group-task {
173 | font-size: 1em;
174 | list-style-type: none;
175 | white-space: nowrap; }
176 |
177 | .nav-group-task-link {
178 | color: #808080; }
179 |
180 | .main-content {
181 | order: 1; }
182 | @media (min-width: 768px) {
183 | .main-content {
184 | order: 2;
185 | flex: 1;
186 | padding-bottom: 60px; } }
187 |
188 | .section {
189 | padding: 0 32px;
190 | border-bottom: 1px solid #ddd; }
191 |
192 | .section-content {
193 | max-width: 834px;
194 | margin: 0 auto;
195 | padding: 16px 0; }
196 |
197 | .section-name {
198 | color: #666;
199 | display: block; }
200 |
201 | .declaration .highlight {
202 | overflow-x: initial;
203 | padding: 8px 0;
204 | margin: 0;
205 | background-color: transparent;
206 | border: none; }
207 |
208 | .task-group-section {
209 | border-top: 1px solid #ddd; }
210 |
211 | .task-group {
212 | padding-top: 0px; }
213 |
214 | .task-name-container a[name]:before {
215 | content: "";
216 | display: block; }
217 |
218 | .item-container {
219 | padding: 0; }
220 |
221 | .item {
222 | padding-top: 8px;
223 | width: 100%;
224 | list-style-type: none; }
225 | .item a[name]:before {
226 | content: "";
227 | display: block; }
228 | .item .token {
229 | padding-left: 3px;
230 | margin-left: 0px;
231 | font-size: 1rem; }
232 | .item .declaration-note {
233 | font-size: .85em;
234 | color: #808080;
235 | font-style: italic; }
236 |
237 | .pointer-container {
238 | border-bottom: 1px solid #ddd;
239 | left: -23px;
240 | padding-bottom: 13px;
241 | position: relative;
242 | width: 110%; }
243 |
244 | .pointer {
245 | left: 21px;
246 | top: 7px;
247 | display: block;
248 | position: absolute;
249 | width: 12px;
250 | height: 12px;
251 | border-left: 1px solid #ddd;
252 | border-top: 1px solid #ddd;
253 | background: #fff;
254 | transform: rotate(45deg); }
255 |
256 | .height-container {
257 | display: none;
258 | position: relative;
259 | width: 100%;
260 | overflow: hidden; }
261 | .height-container .section {
262 | background: #fff;
263 | border: 1px solid #ddd;
264 | border-top-width: 0;
265 | padding-top: 10px;
266 | padding-bottom: 5px;
267 | padding: 8px 16px; }
268 |
269 | .aside, .language {
270 | padding: 6px 12px;
271 | margin: 12px 0;
272 | border-left: 5px solid #dddddd;
273 | overflow-y: hidden; }
274 | .aside .aside-title, .language .aside-title {
275 | font-size: 9px;
276 | letter-spacing: 2px;
277 | text-transform: uppercase;
278 | padding-bottom: 0;
279 | margin: 0;
280 | color: #aaa;
281 | -webkit-user-select: none; }
282 | .aside p:last-child, .language p:last-child {
283 | margin-bottom: 0; }
284 |
285 | .language {
286 | border-left: 5px solid #cde9f4; }
287 | .language .aside-title {
288 | color: #4183c4; }
289 |
290 | .aside-warning {
291 | border-left: 5px solid #ff6666; }
292 | .aside-warning .aside-title {
293 | color: #ff0000; }
294 |
295 | .graybox {
296 | border-collapse: collapse;
297 | width: 100%; }
298 | .graybox p {
299 | margin: 0;
300 | word-break: break-word;
301 | min-width: 50px; }
302 | .graybox td {
303 | border: 1px solid #ddd;
304 | padding: 5px 25px 5px 10px;
305 | vertical-align: middle; }
306 | .graybox tr td:first-of-type {
307 | text-align: right;
308 | padding: 7px;
309 | vertical-align: top;
310 | word-break: normal;
311 | width: 40px; }
312 |
313 | .slightly-smaller {
314 | font-size: 0.9em; }
315 |
316 | .footer {
317 | padding: 8px 16px;
318 | background: #444;
319 | color: #ddd;
320 | font-size: 0.8em; }
321 | .footer p {
322 | margin: 8px 0; }
323 | .footer a {
324 | color: #fff; }
325 |
326 | html.dash .header, html.dash .breadcrumbs, html.dash .navigation {
327 | display: none; }
328 | html.dash .height-container {
329 | display: block; }
330 |
331 | form[role=search] input {
332 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
333 | font-size: 14px;
334 | line-height: 24px;
335 | padding: 0 10px;
336 | margin: 0;
337 | border: none;
338 | border-radius: 1em; }
339 | .loading form[role=search] input {
340 | background: white url(../img/spinner.gif) center right 4px no-repeat; }
341 | form[role=search] .tt-menu {
342 | margin: 0;
343 | min-width: 300px;
344 | background: #fbfbfb;
345 | color: #333;
346 | border: 1px solid #ddd; }
347 | form[role=search] .tt-highlight {
348 | font-weight: bold; }
349 | form[role=search] .tt-suggestion {
350 | font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif;
351 | padding: 0 8px; }
352 | form[role=search] .tt-suggestion span {
353 | display: table-cell;
354 | white-space: nowrap; }
355 | form[role=search] .tt-suggestion .doc-parent-name {
356 | width: 100%;
357 | text-align: right;
358 | font-weight: normal;
359 | font-size: 0.9em;
360 | padding-left: 16px; }
361 | form[role=search] .tt-suggestion:hover,
362 | form[role=search] .tt-suggestion.tt-cursor {
363 | cursor: pointer;
364 | background-color: #4183c4;
365 | color: #fff; }
366 | form[role=search] .tt-suggestion:hover .doc-parent-name,
367 | form[role=search] .tt-suggestion.tt-cursor .doc-parent-name {
368 | color: #fff; }
369 |
--------------------------------------------------------------------------------
/docs/Enums/InvalidDataError.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | InvalidDataError Enumeration Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | Health Reference
46 |
47 | InvalidDataError Enumeration Reference
48 |
49 |
50 |
51 |
52 |
111 |
112 |
113 |
114 |
115 |
116 |
InvalidDataError
117 |
118 |
119 |
public enum InvalidDataError : Error
120 |
121 |
122 |
123 |
InvalidDataError enum
124 |
125 |
Enumeration that represents data errors.
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
142 |
143 |
144 |
145 |
146 |
147 |
A deserialization error occurred.
148 |
149 |
150 |
151 |
Declaration
152 |
153 |
Swift
154 |
case deserialization ( String )
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
173 |
174 |
175 |
176 |
177 |
178 |
A serialization error occurred.
179 |
180 |
181 |
182 |
Declaration
183 |
184 |
Swift
185 |
case serialization ( String )
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
203 |
204 |
205 |
206 |
--------------------------------------------------------------------------------
/docs/Extensions/Date.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Date Extension Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | Health Reference
46 |
47 | Date Extension Reference
48 |
49 |
50 |
51 |
52 |
111 |
112 |
113 |
114 |
115 |
116 |
Date
117 |
118 |
119 |
struct Date : ReferenceConvertible , Comparable , Equatable
120 |
121 |
122 |
123 |
Extension to the Date type.
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
140 |
141 |
142 |
143 |
144 |
145 |
Returns the current time in milliseconds.
146 |
147 |
148 |
149 |
Declaration
150 |
151 |
Swift
152 |
public static func currentTimeMillis () -> UInt64
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
167 |
168 |
169 |
170 |
171 |
172 |
Creates a Date instance from milliseconds.
173 |
174 |
175 |
176 |
Declaration
177 |
178 |
Swift
179 |
public init ( timeInMillis : UInt64 )
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
197 |
198 |
199 |
200 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/Enums/InvalidDataError.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | InvalidDataError Enumeration Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | Health Reference
46 |
47 | InvalidDataError Enumeration Reference
48 |
49 |
50 |
51 |
52 |
111 |
112 |
113 |
114 |
115 |
116 |
InvalidDataError
117 |
118 |
119 |
public enum InvalidDataError : Error
120 |
121 |
122 |
123 |
InvalidDataError enum
124 |
125 |
Enumeration that represents data errors.
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
142 |
143 |
144 |
145 |
146 |
147 |
A deserialization error occurred.
148 |
149 |
150 |
151 |
Declaration
152 |
153 |
Swift
154 |
case deserialization ( String )
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
173 |
174 |
175 |
176 |
177 |
178 |
A serialization error occurred.
179 |
180 |
181 |
182 |
Declaration
183 |
184 |
Swift
185 |
case serialization ( String )
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
203 |
204 |
205 |
206 |
--------------------------------------------------------------------------------
/docs/docsets/Health.docset/Contents/Resources/Documents/Extensions/Date.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Date Extension Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
43 |
44 |
45 | Health Reference
46 |
47 | Date Extension Reference
48 |
49 |
50 |
51 |
52 |
111 |
112 |
113 |
114 |
115 |
116 |
Date
117 |
118 |
119 |
struct Date : ReferenceConvertible , Comparable , Equatable
120 |
121 |
122 |
123 |
Extension to the Date type.
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
140 |
141 |
142 |
143 |
144 |
145 |
Returns the current time in milliseconds.
146 |
147 |
148 |
149 |
Declaration
150 |
151 |
Swift
152 |
public static func currentTimeMillis () -> UInt64
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
167 |
168 |
169 |
170 |
171 |
172 |
Creates a Date instance from milliseconds.
173 |
174 |
175 |
176 |
Declaration
177 |
178 |
Swift
179 |
public init ( timeInMillis : UInt64 )
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
197 |
198 |
199 |
200 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | # Health
25 | The Health package provides a basic infrastructure that Swift applications can use for reporting their overall health status.
26 |
27 | As an application developer, you create an instance of the `Health` class and then register one or more health checks. A health check can be either a closure that conforms to the `HealthCheckClosure` typealias or a class that conforms to the `HealthCheck` protocol. Once you have your health checks in place, you can ask your `Health` instance for its status.
28 |
29 | ## Swift version
30 | The latest version of Health works with the `4.1.2` version of the Swift binaries. You can download this version of the Swift binaries by following this [link](https://swift.org/download/#snapshots).
31 |
32 | ## Usage
33 |
34 | ### Add dependencies
35 |
36 | Add `Health` to the dependencies within your application's `Package.swift` file. Substitute `"x.x.x"` with the latest `Health` [release](https://github.com/Kitura/Health/releases).
37 |
38 | ```swift
39 | .package(url: "https://github.com/Kitura/Health.git", from: "x.x.x")
40 | ```
41 | Add `Health` to your target's dependencies:
42 |
43 | ```Swift
44 | .target(name: "example", dependencies: ["Health"]),
45 | ```
46 |
47 | ### Initialize Health
48 |
49 | The example code below shows how to create a `Health` instance and register your health checks:
50 |
51 | ```swift
52 | import Health
53 |
54 | let health = Health()
55 |
56 | // Add custom checks
57 | health.addCheck(check: MyCheck1())
58 | health.addCheck(check: MyCheck2())
59 | health.addCheck(check: myClosureCheck1)
60 | health.addCheck(check: myClosureCheck1)
61 |
62 | // Get current health status
63 | let count = health.numberOfChecks
64 | let status: Status = health.status
65 | let state: State = status.state
66 | let dictionary = status.toDictionary()
67 | let simpleDictionary = status.toSimpleDictionary()
68 | ```
69 |
70 | The simple dictionary contains a key-value pair that lets you know whether the application is UP or DOWN:
71 |
72 | ```
73 | ["status": "UP"]
74 | ```
75 |
76 | The dictionary contains a key-value pair that lets you know whether the application is UP or DOWN, additional details about the health checks that failed (if any), and a Universal Time Coordinated (UTC) timestamp value:
77 |
78 | ```
79 | ["status": "DOWN", "timestamp": "2017-06-12T18:04:38+0000", "details": ["Cloudant health check.", "A health check closure reported status as DOWN."]]
80 | ```
81 |
82 | Swift applications can use either dictionary, depending on the use case, to report the overall status of the application. For instance, an endpoint on the application could be defined that queries the `Health` object to get the overall status and then send it back to a client as a JSON payload.
83 |
84 | The `Status` structure now conforms to the `Codable` protocol, which enables you to serialize an instance of this structure and send it as a response to a client. If you use this mechanism you don't need to invoke either the `toDictionary()` or the `toSimpleDictionary()` methods in order to obtain the status payload for a client:
85 |
86 | ```
87 | let status: Status = health.status
88 | let payload = try JSONEncoder().encode(status)
89 | // Send payload to client
90 | ```
91 |
92 | ## Caching
93 | When you create an instance of the `Health` class, you can pass an optional argument (named `statusExpirationTime`) to its initializer as shown next:
94 |
95 | ```swift
96 | let health = Health(statusExpirationTime: 30000)
97 | ```
98 |
99 | The `statusExpirationTime` parameter specifies the number of milliseconds that a given instance of `Health` should cache its status for before recomputing it. For instance, if the value assigned to `statusExpirationTime` is `30000` (as shown above), then 30 seconds must elapse before the `Health` instance computes its status again by querying each health check that has been registered. The default value for the `statusExpirationTime` parameter is `30000`.
100 |
101 | ## Implementing a health check
102 | You can implement health checks by either extending the `HealthCheck` protocol or creating a closure that returns a `State` value.
103 |
104 | The following snippet of code shows the implementation of a class named `MyCustomCheck`, which implements the `HealthCheck` protocol:
105 |
106 | ```swift
107 | class MyCustomCheck: HealthCheck {
108 | public var name: String { get { return "MyCustomCheck for XYZ"} }
109 |
110 | public var description: String { get { return "Description for MyCustomCheck..."} }
111 |
112 | public func evaluate() -> State {
113 | let state: State = isConnected() ? State.UP : State.DOWN
114 | return state
115 | }
116 |
117 | private func isConnected() -> Bool {
118 | ...
119 | }
120 | }
121 | ```
122 |
123 | The following snippet of code shows the implementation for a similar health check but using a closure instead:
124 |
125 | ```swift
126 | func myCustomCheck() -> State {
127 | let state: State = isConnected() ? State.UP : State.DOWN
128 | return state
129 | }
130 |
131 | func isConnected() -> Bool {
132 | ...
133 | }
134 | ```
135 |
136 | ## Using Health in a Kitura application
137 | One common use case for this Swift package is to integrate it into a Kitura-based application, as shown below:
138 |
139 | ```swift
140 | import Kitura
141 | import Foundation
142 |
143 | ...
144 |
145 | // Create main objects...
146 | router = Router()
147 |
148 | health = Health()
149 |
150 | // Register health checks...
151 | health.addCheck(check: Microservice1Check())
152 | health.addCheck(check: microservice2Check)
153 |
154 | ...
155 |
156 | // Define /health endpoint that leverages Health
157 | router.get("/health") { request, response, next in
158 | // let status = health.status.toDictionary()
159 | let status = health.status.toSimpleDictionary()
160 | if health.status.state == .UP {
161 | try response.send(json: status).end()
162 | } else {
163 | try response.status(.serviceUnavailable).send(json: status).end()
164 | }
165 | }
166 |
167 | ```
168 |
169 | In the code sample above, the health of the application is exposed through the `/health` endpoint. Cloud environments (e.g. Cloud Foundry, Kubernetes, etc.) can then use the status information returned from the `/health` endpoint to monitor and manage the Swift application instance.
170 |
171 | As an alternative to the implementation shown above for the `/health` endpoint, you can take advantage of the `Codable` protocol available in Swift 4. Since the `Status` struct satisfies the `Codable` protocol, a simpler implementation for the `/health` endpoint can be implemented using the new codable capabilities in Kitura 2.0 as shown below:
172 |
173 | ```swift
174 | ...
175 |
176 | // Define /health endpoint that leverages Health
177 | router.get("/health") { request, response, next in
178 | let status = health.status
179 | if health.status.state == .UP {
180 | try response.status(.OK).send(status).end()
181 | } else {
182 | try response.status(.serviceUnavailable).send(status).end()
183 | }
184 | }
185 |
186 | ...
187 |
188 | ```
189 |
190 | In addition to sending the dictionary response, a server needs to respond with a non-200 status code, if the health state is considered down. This can be accomplished with a status code such as 503 `.serviceUnavailable`. That way, the cloud environment can recognize the negative health response, destroy that instance of the application, and restart the application.
191 |
192 | ## Using Cloud Foundry Environment
193 | If using a Cloud Foundry environment, make sure to update your `manifest.yml` to support health check. In the example above, you would set the `health-check-type` value to `http` and the `health-check-http-endpoint` to the correct health endpoint path, which is `/health` in this case. Review the [health check documentation](https://docs.cloudfoundry.org/devguide/deploy-apps/healthchecks.html) for more details.
194 |
195 | ## API documentation
196 |
197 | For more information visit our [API reference](http://kitura.github.io/Health/).
198 |
199 | ## Community
200 |
201 | We love to talk server-side Swift and Kitura. Join our [Slack](http://swift-at-ibm-slack.mybluemix.net/) to meet the team!
202 |
203 | ## License
204 |
205 | This library is licensed under Apache 2.0. Full license text is available in [LICENSE](https://github.com/Kitura/Health/blob/master/LICENSE.txt).
206 |
--------------------------------------------------------------------------------