~nskaggs/+junk/juju-packaging-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/utils/debugstatus/status.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-27 20:23:11 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161027202311-sux4jk2o73p1d6rg
Re-add src

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2014 Canonical Ltd.
 
2
// Licensed under the LGPLv3, see LICENCE file for details.
 
3
 
 
4
// Package debugstatus provides facilities for inspecting information
 
5
// about a running HTTP service.
 
6
package debugstatus
 
7
 
 
8
import (
 
9
        "fmt"
 
10
        "sync"
 
11
        "time"
 
12
 
 
13
        "gopkg.in/mgo.v2"
 
14
)
 
15
 
 
16
// Check collects the status check results from the given checkers.
 
17
func Check(checkers ...CheckerFunc) map[string]CheckResult {
 
18
        var mu sync.Mutex
 
19
        results := make(map[string]CheckResult, len(checkers))
 
20
 
 
21
        var wg sync.WaitGroup
 
22
        for _, c := range checkers {
 
23
                c := c
 
24
                wg.Add(1)
 
25
                go func() {
 
26
                        defer wg.Done()
 
27
                        t0 := time.Now()
 
28
                        key, result := c()
 
29
                        result.Duration = time.Since(t0)
 
30
                        mu.Lock()
 
31
                        results[key] = result
 
32
                        mu.Unlock()
 
33
                }()
 
34
        }
 
35
        wg.Wait()
 
36
        return results
 
37
}
 
38
 
 
39
// CheckResult holds the result of a single status check.
 
40
type CheckResult struct {
 
41
        // Name is the human readable name for the check.
 
42
        Name string
 
43
 
 
44
        // Value is the check result.
 
45
        Value string
 
46
 
 
47
        // Passed reports whether the check passed.
 
48
        Passed bool
 
49
 
 
50
        // Duration holds the duration that the
 
51
        // status check took to run.
 
52
        Duration time.Duration
 
53
}
 
54
 
 
55
// CheckerFunc represents a function returning the check machine friendly key
 
56
// and the result.
 
57
type CheckerFunc func() (key string, result CheckResult)
 
58
 
 
59
// StartTime holds the time that the code started running.
 
60
var StartTime = time.Now().UTC()
 
61
 
 
62
// ServerStartTime reports the time when the application was started.
 
63
func ServerStartTime() (key string, result CheckResult) {
 
64
        return "server_started", CheckResult{
 
65
                Name:   "Server started",
 
66
                Value:  StartTime.String(),
 
67
                Passed: true,
 
68
        }
 
69
}
 
70
 
 
71
// Connection returns a status checker reporting whether the given Pinger is
 
72
// connected.
 
73
func Connection(p Pinger) CheckerFunc {
 
74
        return func() (key string, result CheckResult) {
 
75
                result.Name = "MongoDB is connected"
 
76
                if err := p.Ping(); err != nil {
 
77
                        result.Value = "Ping error: " + err.Error()
 
78
                        return "mongo_connected", result
 
79
                }
 
80
                result.Value = "Connected"
 
81
                result.Passed = true
 
82
                return "mongo_connected", result
 
83
        }
 
84
}
 
85
 
 
86
// Pinger is an interface that wraps the Ping method.
 
87
// It is implemented by mgo.Session.
 
88
type Pinger interface {
 
89
        Ping() error
 
90
}
 
91
 
 
92
var _ Pinger = (*mgo.Session)(nil)
 
93
 
 
94
// MongoCollections returns a status checker checking that all the
 
95
// expected Mongo collections are present in the database.
 
96
func MongoCollections(c Collector) CheckerFunc {
 
97
        return func() (key string, result CheckResult) {
 
98
                key = "mongo_collections"
 
99
                result.Name = "MongoDB collections"
 
100
                names, err := c.CollectionNames()
 
101
                if err != nil {
 
102
                        result.Value = "Cannot get collections: " + err.Error()
 
103
                        return key, result
 
104
                }
 
105
                var missing []string
 
106
                for _, coll := range c.Collections() {
 
107
                        found := false
 
108
                        for _, name := range names {
 
109
                                if name == coll.Name {
 
110
                                        found = true
 
111
                                        break
 
112
                                }
 
113
                        }
 
114
                        if !found {
 
115
                                missing = append(missing, coll.Name)
 
116
                        }
 
117
                }
 
118
                if len(missing) == 0 {
 
119
                        result.Value = "All required collections exist"
 
120
                        result.Passed = true
 
121
                        return key, result
 
122
                }
 
123
                result.Value = fmt.Sprintf("Missing collections: %s", missing)
 
124
                return key, result
 
125
        }
 
126
}
 
127
 
 
128
// Collector is an interface that groups the methods used to check that
 
129
// a Mongo database has the expected collections.
 
130
// It is usually implemented by types extending mgo.Database to add the
 
131
// Collections() method.
 
132
type Collector interface {
 
133
        // Collections returns the Mongo collections that we expect to exist in
 
134
        // the Mongo database.
 
135
        Collections() []*mgo.Collection
 
136
 
 
137
        // CollectionNames returns the names of the collections actually present in
 
138
        // the Mongo database.
 
139
        CollectionNames() ([]string, error)
 
140
}
 
141
 
 
142
// Rename changes the key and/or result name returned by the given check.
 
143
// It is possible to pass an empty string to avoid changing one of the values.
 
144
// This means that if both key are name are empty, this closure is a no-op.
 
145
func Rename(newKey, newName string, check CheckerFunc) CheckerFunc {
 
146
        return func() (key string, result CheckResult) {
 
147
                key, result = check()
 
148
                if newKey == "" {
 
149
                        newKey = key
 
150
                }
 
151
                if newName != "" {
 
152
                        result.Name = newName
 
153
                }
 
154
                return newKey, result
 
155
        }
 
156
}