|
1 | 1 | [](https://travis-ci.org/st3v/glager)
|
2 | 2 | [](https://coveralls.io/r/st3v/glager?branch=master)
|
3 | 3 |
|
4 |
| -# glager |
| 4 | +glager |
| 5 | +====== |
5 | 6 |
|
6 |
| -Gomega matchers to test lager logging |
| 7 | +Package `glager` provides a set of [Gomega](https://github.com/onsi/gomega) matchers to verify certain events have been logged using the [Lager](https://code.cloudfoundry.org/lager) format. |
| 8 | + |
| 9 | +## Installation |
| 10 | + |
| 11 | +``` |
| 12 | +go get github.com/st3v/glager |
| 13 | +``` |
| 14 | + |
| 15 | +## Matchers |
| 16 | + |
| 17 | +There are two matchers, `glager.HaveLogged` and `glager.ContainSequence`. While their behavior is identical, one might provide better test readability than the other depending on the test scenario. For example, `HaveLogged` works best when use with the included `glager.TestLogger`. |
| 18 | + |
| 19 | +```go |
| 20 | +logger := glager.NewLogger("test") |
| 21 | + |
| 22 | +... |
| 23 | + |
| 24 | +Expect(logger).To(HaveLogged(...)) |
| 25 | +``` |
| 26 | + |
| 27 | +`ContainSequence` on the other hand reads nice when used with `gbytes.Buffer` or `io.Reader`. |
| 28 | + |
| 29 | +```go |
| 30 | +log := gbytes.NewBuffer() |
| 31 | +logger := lager.NewLogger("test") |
| 32 | +logger.RegisterSink(lager.NewWriterSink(log, lager.DEBUG)) |
| 33 | + |
| 34 | +... |
| 35 | + |
| 36 | +Expect(log).To(ContainSequence(...)) |
| 37 | +``` |
| 38 | + |
| 39 | +Both matchers verify that a certain sequence of log entries have been written using the lager logging format. Depending on the expected log level a log entry passed to the matcher can be specified using one the following methods. |
| 40 | + |
| 41 | +```go |
| 42 | +// Info specifies a log entry with level lager.INFO. |
| 43 | +glager.Info(...) |
| 44 | + |
| 45 | +// Debug specifies a log entry with level lager.DEBUG. |
| 46 | +glager.Debug(...) |
| 47 | + |
| 48 | +// Error specifies a log entry with level lager.ERROR. |
| 49 | +glager.Error(...) |
| 50 | + |
| 51 | +// Fatal specifies a log entry with level lager.FATAL. |
| 52 | +glager.Fatal(...) |
| 53 | +``` |
| 54 | + |
| 55 | +All of the above methods take a set of optional arguments used to specify the expected details of a given log entry. The available properties are: |
| 56 | + |
| 57 | + |
| 58 | +```go |
| 59 | +// Source specifies a string that indicates the log source. The source of a |
| 60 | +// lager logger is usually specified at instantiation time. Source is sometimes |
| 61 | +// also called component. |
| 62 | +glager.Source("source") |
| 63 | + |
| 64 | +// Message specifies a string that represent the message of a given log entry. |
| 65 | +glager.Message("message") |
| 66 | + |
| 67 | +// Action is an alias for Message, lager uses the term action is used |
| 68 | +// alternatively to message. |
| 69 | +glager.Action("action") |
| 70 | + |
| 71 | +// Data specifies the data logged by a given log entry. Arguments are specified |
| 72 | +// as an alternating sequence of keys (string) and values (interface{}). |
| 73 | +glager.Data("key1", "value1", "key2", "value2", ...) |
| 74 | + |
| 75 | +// AnyErr can be used to match an Error or Fatal log entry, without matching the |
| 76 | +// actual error that has been logged. |
| 77 | +glager.AnyErr |
| 78 | +``` |
| 79 | + |
| 80 | +When passing a sequence of log entries to the matcher, you only have to include the entries you are actually interested in. They don't have to be contiguous entries in the log. All that matters is their properties and their respective order. |
| 81 | + |
| 82 | +Similarly, you don't have to specify all possible properties of a given log entry but only the ones you actually care about. For example, if all that matters to you is that there were two subsequent calls to `logger.Info`, you could use: |
| 83 | + |
| 84 | +```go |
| 85 | +Expect(logger).To(HaveLogged(Info(), Info())) |
| 86 | +``` |
| 87 | + |
| 88 | +If you care about the data that has been logged something like the following might work for you. |
| 89 | + |
| 90 | +```go |
| 91 | +Expect(logger).To(HaveLogged( |
| 92 | + Info(Data("some-string", "string-value")), |
| 93 | + Info(Data("some-integer", 12345)), |
| 94 | +)) |
| 95 | +``` |
| 96 | + |
| 97 | +## Example Usage |
| 98 | + |
| 99 | +See `example_test.go` for executable examples. |
| 100 | + |
| 101 | +```go |
| 102 | +import ( |
| 103 | + "code.cloudfoundry.com/lager" |
| 104 | + . "github.com/onsi/gomega" |
| 105 | + . "github.com/st3v/glager" |
| 106 | +) |
| 107 | + |
| 108 | +... |
| 109 | + |
| 110 | +// instantiate glager.TestLogger inside your test and |
| 111 | +logger := NewLogger("test") |
| 112 | + |
| 113 | +// pass logger to your code and use it in there to log stuff |
| 114 | +func(logger *lager.Logger) { |
| 115 | + logger.Info("myFunc", lager.Data(map[string]interface{}{ |
| 116 | + "event": "start", |
| 117 | + })) |
| 118 | + |
| 119 | + logger.Debug("myFunc", lager.Data(map[string]interface{}{ |
| 120 | + "some": "stuff", |
| 121 | + "more": "stuff", |
| 122 | + })) |
| 123 | + |
| 124 | + logger.Error("myFunc", |
| 125 | + errors.New("some error"), |
| 126 | + lager.Data(map[string]interface{}{ |
| 127 | + "details": "stuff", |
| 128 | + }), |
| 129 | + ) |
| 130 | + |
| 131 | + logger.Info("myFunc", lager.Data(map[string]interface{}{ |
| 132 | + "event": "done", |
| 133 | + })) |
| 134 | +}() |
| 135 | + |
| 136 | +... |
| 137 | + |
| 138 | +// verify logging inside your test |
| 139 | +Expect(logger).To(HaveLogged( |
| 140 | + Info( |
| 141 | + Message("test.myFunc"), |
| 142 | + Data("event", "start"), |
| 143 | + ), |
| 144 | + Debug( |
| 145 | + Data("more", "stuff"), |
| 146 | + ), |
| 147 | + Error(AnyErr), |
| 148 | +)) |
| 149 | + |
| 150 | +... |
| 151 | +``` |
| 152 | + |
| 153 | +## License |
| 154 | +`glager` is licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/st3v/glager/blob/master/LICENSE) for details. |
0 commit comments