vendor go-logging + camlistore/lock
Juan Batiz-Benet committed
Sep 30, 2014 at 03:33 UTC
17f147eff824e83e17b95b3fdcaae653cabb96c3
34 files changed
+2774
-2
Godeps/Godeps.json
+8
@@ -38,6 +38,10 @@
38
"Comment": "null-15",
39
"Rev": "12e4b4183793ac4b061921e7980845e750679fd0"
40
},
41
+ {
42
+ "ImportPath": "github.com/camlistore/lock",
43
+ "Rev": "ae27720f340952636b826119b58130b9c1a847a0"
44
+ },
45
{
46
"ImportPath": "github.com/gonuts/flag",
47
"Rev": "741a6cbd37a30dedc93f817e7de6aaf0ca38a493"
@@ -68,6 +72,10 @@
72
"Comment": "0.1.0-5-g1976046",
73
"Rev": "1976046c2b0db0b668791b3e541d76a38b7c1af7"
74
},
75
+ {
76
+ "ImportPath": "github.com/op/go-logging",
77
+ "Rev": "3df864a88c7f005e676db4f026a4fe2f14929be3"
78
+ },
79
{
80
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
81
"Rev": "99056d50e56252fbe0021d5c893defca5a76baf8"
Godeps/_workspace/src/github.com/camlistore/lock/.gitignore
new
+1
@@ -0,0 +1 @@
1
+*~
Godeps/_workspace/src/github.com/camlistore/lock/COPYING
new
+202
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
Godeps/_workspace/src/github.com/camlistore/lock/README.txt
new
+3
@@ -0,0 +1,3 @@
1
+File locking library.
2
+
3
+See http://godoc.org/github.com/camlistore/lock
Godeps/_workspace/src/github.com/camlistore/lock/lock.go
new
+158
@@ -0,0 +1,158 @@
1
+/*
2
+Copyright 2013 The Go Authors
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
+package lock
18
+
19
+import (
20
+ "encoding/json"
21
+ "fmt"
22
+ "io"
23
+ "os"
24
+ "path/filepath"
25
+ "sync"
26
+)
27
+
28
+// Lock locks the given file, creating the file if necessary. If the
29
+// file already exists, it must have zero size or an error is returned.
30
+// The lock is an exclusive lock (a write lock), but locked files
31
+// should neither be read from nor written to. Such files should have
32
+// zero size and only exist to co-ordinate ownership across processes.
33
+//
34
+// A nil Closer is returned if an error occurred. Otherwise, close that
35
+// Closer to release the lock.
36
+//
37
+// On Linux, FreeBSD and OSX, a lock has the same semantics as fcntl(2)'s
38
+// advisory locks. In particular, closing any other file descriptor for the
39
+// same file will release the lock prematurely.
40
+//
41
+// Attempting to lock a file that is already locked by the current process
42
+// has undefined behavior.
43
+//
44
+// On other operating systems, lock will fallback to using the presence and
45
+// content of a file named name + '.lock' to implement locking behavior.
46
+func Lock(name string) (io.Closer, error) {
47
+ return lockFn(name)
48
+}
49
+
50
+var lockFn = lockPortable
51
+
52
+// Portable version not using fcntl. Doesn't handle crashes as gracefully,
53
+// since it can leave stale lock files.
54
+// TODO: write pid of owner to lock file and on race see if pid is
55
+// still alive?
56
+func lockPortable(name string) (io.Closer, error) {
57
+ absName, err := filepath.Abs(name)
58
+ if err != nil {
59
+ return nil, fmt.Errorf("can't Lock file %q: can't find abs path: %v", name, err)
60
+ }
61
+ fi, err := os.Stat(absName)
62
+ if err == nil && fi.Size() > 0 {
63
+ if isStaleLock(absName) {
64
+ os.Remove(absName)
65
+ } else {
66
+ return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
67
+ }
68
+ }
69
+ f, err := os.OpenFile(absName, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_EXCL, 0666)
70
+ if err != nil {
71
+ return nil, fmt.Errorf("failed to create lock file %s %v", absName, err)
72
+ }
73
+ if err := json.NewEncoder(f).Encode(&pidLockMeta{OwnerPID: os.Getpid()}); err != nil {
74
+ return nil, err
75
+ }
76
+ return &lockCloser{f: f, abs: absName}, nil
77
+}
78
+
79
+type pidLockMeta struct {
80
+ OwnerPID int
81
+}
82
+
83
+func isStaleLock(path string) bool {
84
+ f, err := os.Open(path)
85
+ if err != nil {
86
+ return false
87
+ }
88
+ defer f.Close()
89
+ var meta pidLockMeta
90
+ if json.NewDecoder(f).Decode(&meta) != nil {
91
+ return false
92
+ }
93
+ if meta.OwnerPID == 0 {
94
+ return false
95
+ }
96
+ p, err := os.FindProcess(meta.OwnerPID)
97
+ if err != nil {
98
+ // e.g. on Windows
99
+ return true
100
+ }
101
+ // On unix, os.FindProcess always is true, so we have to send
102
+ // it a signal to see if it's alive.
103
+ if signalZero != nil {
104
+ if p.Signal(signalZero) != nil {
105
+ return true
106
+ }
107
+ }
108
+ return false
109
+}
110
+
111
+var signalZero os.Signal // nil or set by lock_sigzero.go
112
+
113
+type lockCloser struct {
114
+ f *os.File
115
+ abs string
116
+ once sync.Once
117
+ err error
118
+}
119
+
120
+func (lc *lockCloser) Close() error {
121
+ lc.once.Do(lc.close)
122
+ return lc.err
123
+}
124
+
125
+func (lc *lockCloser) close() {
126
+ if err := lc.f.Close(); err != nil {
127
+ lc.err = err
128
+ }
129
+ if err := os.Remove(lc.abs); err != nil {
130
+ lc.err = err
131
+ }
132
+}
133
+
134
+var (
135
+ lockmu sync.Mutex
136
+ locked = map[string]bool{} // abs path -> true
137
+)
138
+
139
+// unlocker is used by the darwin and linux implementations with fcntl
140
+// advisory locks.
141
+type unlocker struct {
142
+ f *os.File
143
+ abs string
144
+}
145
+
146
+func (u *unlocker) Close() error {
147
+ lockmu.Lock()
148
+ // Remove is not necessary but it's nice for us to clean up.
149
+ // If we do do this, though, it needs to be before the
150
+ // u.f.Close below.
151
+ os.Remove(u.abs)
152
+ if err := u.f.Close(); err != nil {
153
+ return err
154
+ }
155
+ delete(locked, u.abs)
156
+ lockmu.Unlock()
157
+ return nil
158
+}
Godeps/_workspace/src/github.com/camlistore/lock/lock_appengine.go
new
+32
@@ -0,0 +1,32 @@
1
+// +build appengine
2
+
3
+/*
4
+Copyright 2013 The Go Authors
5
+
6
+Licensed under the Apache License, Version 2.0 (the "License");
7
+you may not use this file except in compliance with the License.
8
+You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+Unless required by applicable law or agreed to in writing, software
13
+distributed under the License is distributed on an "AS IS" BASIS,
14
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+See the License for the specific language governing permissions and
16
+limitations under the License.
17
+*/
18
+
19
+package lock
20
+
21
+import (
22
+ "errors"
23
+ "io"
24
+)
25
+
26
+func init() {
27
+ lockFn = lockAppEngine
28
+}
29
+
30
+func lockAppEngine(name string) (io.Closer, error) {
31
+ return nil, errors.New("Lock not available on App Engine")
32
+}
Godeps/_workspace/src/github.com/camlistore/lock/lock_darwin_amd64.go
new
+80
@@ -0,0 +1,80 @@
1
+// +build darwin,amd64
2
+// +build !appengine
3
+
4
+/*
5
+Copyright 2013 The Go Authors
6
+
7
+Licensed under the Apache License, Version 2.0 (the "License");
8
+you may not use this file except in compliance with the License.
9
+You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+Unless required by applicable law or agreed to in writing, software
14
+distributed under the License is distributed on an "AS IS" BASIS,
15
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+See the License for the specific language governing permissions and
17
+limitations under the License.
18
+*/
19
+
20
+package lock
21
+
22
+import (
23
+ "fmt"
24
+ "io"
25
+ "os"
26
+ "path/filepath"
27
+ "syscall"
28
+ "unsafe"
29
+)
30
+
31
+func init() {
32
+ lockFn = lockFcntl
33
+}
34
+
35
+func lockFcntl(name string) (io.Closer, error) {
36
+ abs, err := filepath.Abs(name)
37
+ if err != nil {
38
+ return nil, err
39
+ }
40
+ lockmu.Lock()
41
+ if locked[abs] {
42
+ lockmu.Unlock()
43
+ return nil, fmt.Errorf("file %q already locked", abs)
44
+ }
45
+ locked[abs] = true
46
+ lockmu.Unlock()
47
+
48
+ fi, err := os.Stat(name)
49
+ if err == nil && fi.Size() > 0 {
50
+ return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
51
+ }
52
+
53
+ f, err := os.Create(name)
54
+ if err != nil {
55
+ return nil, fmt.Errorf("Lock Create of %s (abs: %s) failed: %v", name, abs, err)
56
+ }
57
+
58
+ // This type matches C's "struct flock" defined in /usr/include/sys/fcntl.h.
59
+ // TODO: move this into the standard syscall package.
60
+ k := struct {
61
+ Start uint64 // sizeof(off_t): 8
62
+ Len uint64 // sizeof(off_t): 8
63
+ Pid uint32 // sizeof(pid_t): 4
64
+ Type uint16 // sizeof(short): 2
65
+ Whence uint16 // sizeof(short): 2
66
+ }{
67
+ Type: syscall.F_WRLCK,
68
+ Whence: uint16(os.SEEK_SET),
69
+ Start: 0,
70
+ Len: 0, // 0 means to lock the entire file.
71
+ Pid: uint32(os.Getpid()),
72
+ }
73
+
74
+ _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k)))
75
+ if errno != 0 {
76
+ f.Close()
77
+ return nil, errno
78
+ }
79
+ return &unlocker{f, abs}, nil
80
+}
Godeps/_workspace/src/github.com/camlistore/lock/lock_freebsd.go
new
+79
@@ -0,0 +1,79 @@
1
+/*
2
+Copyright 2013 The Go Authors
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
+package lock
18
+
19
+import (
20
+ "fmt"
21
+ "io"
22
+ "os"
23
+ "path/filepath"
24
+ "syscall"
25
+ "unsafe"
26
+)
27
+
28
+func init() {
29
+ lockFn = lockFcntl
30
+}
31
+
32
+func lockFcntl(name string) (io.Closer, error) {
33
+ abs, err := filepath.Abs(name)
34
+ if err != nil {
35
+ return nil, err
36
+ }
37
+ lockmu.Lock()
38
+ if locked[abs] {
39
+ lockmu.Unlock()
40
+ return nil, fmt.Errorf("file %q already locked", abs)
41
+ }
42
+ locked[abs] = true
43
+ lockmu.Unlock()
44
+
45
+ fi, err := os.Stat(name)
46
+ if err == nil && fi.Size() > 0 {
47
+ return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
48
+ }
49
+
50
+ f, err := os.Create(name)
51
+ if err != nil {
52
+ return nil, err
53
+ }
54
+
55
+ // This type matches C's "struct flock" defined in /usr/include/fcntl.h.
56
+ // TODO: move this into the standard syscall package.
57
+ k := struct {
58
+ Start int64 /* off_t starting offset */
59
+ Len int64 /* off_t len = 0 means until end of file */
60
+ Pid int32 /* pid_t lock owner */
61
+ Type int16 /* short lock type: read/write, etc. */
62
+ Whence int16 /* short type of l_start */
63
+ Sysid int32 /* int remote system id or zero for local */
64
+ }{
65
+ Start: 0,
66
+ Len: 0, // 0 means to lock the entire file.
67
+ Pid: int32(os.Getpid()),
68
+ Type: syscall.F_WRLCK,
69
+ Whence: int16(os.SEEK_SET),
70
+ Sysid: 0,
71
+ }
72
+
73
+ _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k)))
74
+ if errno != 0 {
75
+ f.Close()
76
+ return nil, errno
77
+ }
78
+ return &unlocker{f, abs}, nil
79
+}
Godeps/_workspace/src/github.com/camlistore/lock/lock_linux_amd64.go
new
+80
@@ -0,0 +1,80 @@
1
+// +build linux,amd64
2
+// +build !appengine
3
+
4
+/*
5
+Copyright 2013 The Go Authors
6
+
7
+Licensed under the Apache License, Version 2.0 (the "License");
8
+you may not use this file except in compliance with the License.
9
+You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+Unless required by applicable law or agreed to in writing, software
14
+distributed under the License is distributed on an "AS IS" BASIS,
15
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+See the License for the specific language governing permissions and
17
+limitations under the License.
18
+*/
19
+
20
+package lock
21
+
22
+import (
23
+ "fmt"
24
+ "io"
25
+ "os"
26
+ "path/filepath"
27
+ "syscall"
28
+ "unsafe"
29
+)
30
+
31
+func init() {
32
+ lockFn = lockFcntl
33
+}
34
+
35
+func lockFcntl(name string) (io.Closer, error) {
36
+ abs, err := filepath.Abs(name)
37
+ if err != nil {
38
+ return nil, err
39
+ }
40
+ lockmu.Lock()
41
+ if locked[abs] {
42
+ lockmu.Unlock()
43
+ return nil, fmt.Errorf("file %q already locked", abs)
44
+ }
45
+ locked[abs] = true
46
+ lockmu.Unlock()
47
+
48
+ fi, err := os.Stat(name)
49
+ if err == nil && fi.Size() > 0 {
50
+ return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
51
+ }
52
+
53
+ f, err := os.Create(name)
54
+ if err != nil {
55
+ return nil, err
56
+ }
57
+
58
+ // This type matches C's "struct flock" defined in /usr/include/bits/fcntl.h.
59
+ // TODO: move this into the standard syscall package.
60
+ k := struct {
61
+ Type uint32
62
+ Whence uint32
63
+ Start uint64
64
+ Len uint64
65
+ Pid uint32
66
+ }{
67
+ Type: syscall.F_WRLCK,
68
+ Whence: uint32(os.SEEK_SET),
69
+ Start: 0,
70
+ Len: 0, // 0 means to lock the entire file.
71
+ Pid: uint32(os.Getpid()),
72
+ }
73
+
74
+ _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k)))
75
+ if errno != 0 {
76
+ f.Close()
77
+ return nil, errno
78
+ }
79
+ return &unlocker{f, abs}, nil
80
+}
Godeps/_workspace/src/github.com/camlistore/lock/lock_linux_arm.go
new
+81
@@ -0,0 +1,81 @@
1
+// +build linux,arm
2
+// +build !appengine
3
+
4
+/*
5
+Copyright 2013 The Go Authors
6
+
7
+Licensed under the Apache License, Version 2.0 (the "License");
8
+you may not use this file except in compliance with the License.
9
+You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+Unless required by applicable law or agreed to in writing, software
14
+distributed under the License is distributed on an "AS IS" BASIS,
15
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+See the License for the specific language governing permissions and
17
+limitations under the License.
18
+*/
19
+
20
+package lock
21
+
22
+import (
23
+ "fmt"
24
+ "io"
25
+ "os"
26
+ "path/filepath"
27
+ "syscall"
28
+ "unsafe"
29
+)
30
+
31
+func init() {
32
+ lockFn = lockFcntl
33
+}
34
+
35
+func lockFcntl(name string) (io.Closer, error) {
36
+ abs, err := filepath.Abs(name)
37
+ if err != nil {
38
+ return nil, err
39
+ }
40
+ lockmu.Lock()
41
+ if locked[abs] {
42
+ lockmu.Unlock()
43
+ return nil, fmt.Errorf("file %q already locked", abs)
44
+ }
45
+ locked[abs] = true
46
+ lockmu.Unlock()
47
+
48
+ fi, err := os.Stat(name)
49
+ if err == nil && fi.Size() > 0 {
50
+ return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
51
+ }
52
+
53
+ f, err := os.Create(name)
54
+ if err != nil {
55
+ return nil, err
56
+ }
57
+
58
+ // This type matches C's "struct flock" defined in /usr/include/bits/fcntl.h.
59
+ // TODO: move this into the standard syscall package.
60
+ k := struct {
61
+ Type uint16
62
+ Whence uint16
63
+ Start uint32
64
+ Len uint32
65
+ Pid uint32
66
+ }{
67
+ Type: syscall.F_WRLCK,
68
+ Whence: uint16(os.SEEK_SET),
69
+ Start: 0,
70
+ Len: 0, // 0 means to lock the entire file.
71
+ Pid: uint32(os.Getpid()),
72
+ }
73
+
74
+ const F_SETLK = 6 // actual value. syscall package is wrong: golang.org/issue/7059
75
+ _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(F_SETLK), uintptr(unsafe.Pointer(&k)))
76
+ if errno != 0 {
77
+ f.Close()
78
+ return nil, errno
79
+ }
80
+ return &unlocker{f, abs}, nil
81
+}
Godeps/_workspace/src/github.com/camlistore/lock/lock_plan9.go
new
+55
@@ -0,0 +1,55 @@
1
+/*
2
+Copyright 2013 The Go Authors
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
+package lock
18
+
19
+import (
20
+ "fmt"
21
+ "io"
22
+ "os"
23
+ "path/filepath"
24
+)
25
+
26
+func init() {
27
+ lockFn = lockPlan9
28
+}
29
+
30
+func lockPlan9(name string) (io.Closer, error) {
31
+ var f *os.File
32
+ abs, err := filepath.Abs(name)
33
+ if err != nil {
34
+ return nil, err
35
+ }
36
+ lockmu.Lock()
37
+ if locked[abs] {
38
+ lockmu.Unlock()
39
+ return nil, fmt.Errorf("file %q already locked", abs)
40
+ }
41
+ locked[abs] = true
42
+ lockmu.Unlock()
43
+
44
+ fi, err := os.Stat(name)
45
+ if err == nil && fi.Size() > 0 {
46
+ return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name)
47
+ }
48
+
49
+ f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE, os.ModeExclusive|0644)
50
+ if err != nil {
51
+ return nil, fmt.Errorf("Lock Create of %s (abs: %s) failed: %v", name, abs, err)
52
+ }
53
+
54
+ return &unlocker{f, abs}, nil
55
+}
Godeps/_workspace/src/github.com/camlistore/lock/lock_sigzero.go
new
+26
@@ -0,0 +1,26 @@
1
+// +build !appengine
2
+// +build linux darwin freebsd openbsd netbsd dragonfly
3
+
4
+/*
5
+Copyright 2013 The Go Authors
6
+
7
+Licensed under the Apache License, Version 2.0 (the "License");
8
+you may not use this file except in compliance with the License.
9
+You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+Unless required by applicable law or agreed to in writing, software
14
+distributed under the License is distributed on an "AS IS" BASIS,
15
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+See the License for the specific language governing permissions and
17
+limitations under the License.
18
+*/
19
+
20
+package lock
21
+
22
+import "syscall"
23
+
24
+func init() {
25
+ signalZero = syscall.Signal(0)
26
+}
Godeps/_workspace/src/github.com/camlistore/lock/lock_test.go
new
+131
@@ -0,0 +1,131 @@
1
+/*
2
+Copyright 2013 The Go Authors
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
+package lock
18
+
19
+import (
20
+ "fmt"
21
+ "io/ioutil"
22
+ "log"
23
+ "os"
24
+ "os/exec"
25
+ "path/filepath"
26
+ "strconv"
27
+ "testing"
28
+)
29
+
30
+func TestLock(t *testing.T) {
31
+ testLock(t, false)
32
+}
33
+
34
+func TestLockPortable(t *testing.T) {
35
+ testLock(t, true)
36
+}
37
+
38
+func TestLockInChild(t *testing.T) {
39
+ f := os.Getenv("TEST_LOCK_FILE")
40
+ if f == "" {
41
+ // not child
42
+ return
43
+ }
44
+ lock := Lock
45
+ if v, _ := strconv.ParseBool(os.Getenv("TEST_LOCK_PORTABLE")); v {
46
+ lock = lockPortable
47
+ }
48
+
49
+ lk, err := lock(f)
50
+ if err != nil {
51
+ log.Fatalf("Lock failed: %v", err)
52
+ }
53
+
54
+ if v, _ := strconv.ParseBool(os.Getenv("TEST_LOCK_CRASH")); v {
55
+ // Simulate a crash, or at least not unlocking the
56
+ // lock. We still exit 0 just to simplify the parent
57
+ // process exec code.
58
+ os.Exit(0)
59
+ }
60
+ lk.Close()
61
+}
62
+
63
+func testLock(t *testing.T, portable bool) {
64
+ lock := Lock
65
+ if portable {
66
+ lock = lockPortable
67
+ }
68
+
69
+ td, err := ioutil.TempDir("", "")
70
+ if err != nil {
71
+ t.Fatal(err)
72
+ }
73
+ defer os.RemoveAll(td)
74
+
75
+ path := filepath.Join(td, "foo.lock")
76
+
77
+ childLock := func(crash bool) error {
78
+ cmd := exec.Command(os.Args[0], "-test.run=LockInChild$")
79
+ cmd.Env = []string{"TEST_LOCK_FILE=" + path}
80
+ if portable {
81
+ cmd.Env = append(cmd.Env, "TEST_LOCK_PORTABLE=1")
82
+ }
83
+ if crash {
84
+ cmd.Env = append(cmd.Env, "TEST_LOCK_CRASH=1")
85
+ }
86
+ out, err := cmd.CombinedOutput()
87
+ t.Logf("Child output: %q (err %v)", out, err)
88
+ if err != nil {
89
+ return fmt.Errorf("Child Process lock of %s failed: %v %s", path, err, out)
90
+ }
91
+ return nil
92
+ }
93
+
94
+ t.Logf("Locking in crashing child...")
95
+ if err := childLock(true); err != nil {
96
+ t.Fatalf("first lock in child process: %v", err)
97
+ }
98
+
99
+ t.Logf("Locking+unlocking in child...")
100
+ if err := childLock(false); err != nil {
101
+ t.Fatalf("lock in child process after crashing child: %v", err)
102
+ }
103
+
104
+ t.Logf("Locking in parent...")
105
+ lk1, err := lock(path)
106
+ if err != nil {
107
+ t.Fatal(err)
108
+ }
109
+
110
+ t.Logf("Again in parent...")
111
+ _, err = lock(path)
112
+ if err == nil {
113
+ t.Fatal("expected second lock to fail")
114
+ }
115
+
116
+ t.Logf("Locking in child...")
117
+ if childLock(false) == nil {
118
+ t.Fatalf("expected lock in child process to fail")
119
+ }
120
+
121
+ t.Logf("Unlocking lock in parent")
122
+ if err := lk1.Close(); err != nil {
123
+ t.Fatal(err)
124
+ }
125
+
126
+ lk3, err := lock(path)
127
+ if err != nil {
128
+ t.Fatal(err)
129
+ }
130
+ lk3.Close()
131
+}
Godeps/_workspace/src/github.com/op/go-logging/.travis.yml
new
+6
@@ -0,0 +1,6 @@
1
+language: go
2
+
3
+go:
4
+ - 1.0
5
+ - 1.1
6
+ - tip
Godeps/_workspace/src/github.com/op/go-logging/CONTRIBUTORS
new
+5
@@ -0,0 +1,5 @@
1
+Alec Thomas <alec@swapoff.org>
2
+Guilhem Lettron <guilhem.lettron@optiflows.com>
3
+Ivan Daniluk <ivan.daniluk@gmail.com>
4
+Nimi Wariboko Jr <nimi@channelmeter.com>
5
+Róbert Selvek <robert.selvek@gmail.com>
Godeps/_workspace/src/github.com/op/go-logging/LICENSE
new
+27
@@ -0,0 +1,27 @@
1
+Copyright (c) 2013 Örjan Persson. All rights reserved.
2
+
3
+Redistribution and use in source and binary forms, with or without
4
+modification, are permitted provided that the following conditions are
5
+met:
6
+
7
+ * Redistributions of source code must retain the above copyright
8
+notice, this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above
10
+copyright notice, this list of conditions and the following disclaimer
11
+in the documentation and/or other materials provided with the
12
+distribution.
13
+ * Neither the name of Google Inc. nor the names of its
14
+contributors may be used to endorse or promote products derived from
15
+this software without specific prior written permission.
16
+
17
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Godeps/_workspace/src/github.com/op/go-logging/README.md
new
+83
@@ -0,0 +1,83 @@
1
+## Golang logging library
2
+
3
+[](https://travis-ci.org/op/go-logging)
4
+
5
+Package logging implements a logging infrastructure for Go. Its output format
6
+is customizable and supports different logging backends like syslog, file and
7
+memory. Multiple backends can be utilized with different log levels per backend
8
+and logger.
9
+
10
+## Example
11
+
12
+Let's have a look at an [example](examples/example.go) which demonstrates most
13
+of the features found in this library.
14
+
15
+[](examples/example.go)
16
+
17
+```go
18
+package main
19
+
20
+import (
21
+ "os"
22
+
23
+ "github.com/op/go-logging"
24
+)
25
+
26
+var log = logging.MustGetLogger("example")
27
+
28
+// Example format string. Everything except the message has a custom color
29
+// which is dependent on the log level. Many fields have a custom output
30
+// formatting too, eg. the time returns the hour down to the milli second.
31
+var format = "%{color}%{time:15:04:05.000000} ▶ %{level:.4s} %{id:03x}%{color:reset} %{message}"
32
+
33
+// Password is just an example type implementing the Redactor interface. Any
34
+// time this is logged, the Redacted() function will be called.
35
+type Password string
36
+
37
+func (p Password) Redacted() interface{} {
38
+ return logging.Redact(string(p))
39
+}
40
+
41
+func main() {
42
+ // Setup one stderr and one syslog backend and combine them both into one
43
+ // logging backend. By default stderr is used with the standard log flag.
44
+ logBackend := logging.NewLogBackend(os.Stderr, "", 0)
45
+ syslogBackend, err := logging.NewSyslogBackend("")
46
+ if err != nil {
47
+ log.Fatal(err)
48
+ }
49
+ logging.SetBackend(logBackend, syslogBackend)
50
+ logging.SetFormatter(logging.MustStringFormatter(format))
51
+
52
+ // For "example", set the log level to DEBUG and ERROR.
53
+ for _, level := range []logging.Level{logging.DEBUG, logging.ERROR} {
54
+ logging.SetLevel(level, "example")
55
+
56
+ log.Debug("debug %s", Password("secret"))
57
+ log.Info("info")
58
+ log.Notice("notice")
59
+ log.Warning("warning")
60
+ log.Error("err")
61
+ log.Critical("crit")
62
+ }
63
+}
64
+```
65
+
66
+## Installing
67
+
68
+### Using *go get*
69
+
70
+ $ go get github.com/op/go-logging
71
+
72
+After this command *go-logging* is ready to use. Its source will be in:
73
+
74
+ $GOROOT/src/pkg/github.com/op/go-logging
75
+
76
+You can use `go get -u` to update the package.
77
+
78
+## Documentation
79
+
80
+For docs, see http://godoc.org/github.com/op/go-logging or run:
81
+
82
+ $ godoc github.com/op/go-logging
83
+
Godeps/_workspace/src/github.com/op/go-logging/backend.go
new
+39
@@ -0,0 +1,39 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+// defaultBackend is the backend used for all logging calls.
8
+var defaultBackend LeveledBackend
9
+
10
+// Backend is the interface which a log backend need to implement to be able to
11
+// be used as a logging backend.
12
+type Backend interface {
13
+ Log(Level, int, *Record) error
14
+}
15
+
16
+// Set backend replaces the backend currently set with the given new logging
17
+// backend.
18
+func SetBackend(backends ...Backend) LeveledBackend {
19
+ var backend Backend
20
+ if len(backends) == 1 {
21
+ backend = backends[0]
22
+ } else {
23
+ backend = MultiLogger(backends...)
24
+ }
25
+
26
+ defaultBackend = AddModuleLevel(backend)
27
+ return defaultBackend
28
+}
29
+
30
+// SetLevel sets the logging level for the specified module. The module
31
+// corresponds to the string specified in GetLogger.
32
+func SetLevel(level Level, module string) {
33
+ defaultBackend.SetLevel(level, module)
34
+}
35
+
36
+// GetLevel returns the logging level for the specified module.
37
+func GetLevel(module string) Level {
38
+ return defaultBackend.GetLevel(module)
39
+}
Godeps/_workspace/src/github.com/op/go-logging/examples/example.go
new
+46
@@ -0,0 +1,46 @@
1
+package main
2
+
3
+import (
4
+ "os"
5
+
6
+ "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/op/go-logging"
7
+)
8
+
9
+var log = logging.MustGetLogger("example")
10
+
11
+// Example format string. Everything except the message has a custom color
12
+// which is dependent on the log level. Many fields have a custom output
13
+// formatting too, eg. the time returns the hour down to the milli second.
14
+var format = "%{color}%{time:15:04:05.000000} %{shortfunc} ▶ %{level:.4s} %{id:03x}%{color:reset} %{message}"
15
+
16
+// Password is just an example type implementing the Redactor interface. Any
17
+// time this is logged, the Redacted() function will be called.
18
+type Password string
19
+
20
+func (p Password) Redacted() interface{} {
21
+ return logging.Redact(string(p))
22
+}
23
+
24
+func main() {
25
+ // Setup one stderr and one syslog backend and combine them both into one
26
+ // logging backend. By default stderr is used with the standard log flag.
27
+ logBackend := logging.NewLogBackend(os.Stderr, "", 0)
28
+ syslogBackend, err := logging.NewSyslogBackend("")
29
+ if err != nil {
30
+ log.Fatal(err)
31
+ }
32
+ logging.SetBackend(logBackend, syslogBackend)
33
+ logging.SetFormatter(logging.MustStringFormatter(format))
34
+
35
+ // For "example", set the log level to DEBUG and ERROR.
36
+ for _, level := range []logging.Level{logging.DEBUG, logging.ERROR} {
37
+ logging.SetLevel(level, "example")
38
+
39
+ log.Debug("debug %s", Password("secret"))
40
+ log.Info("info")
41
+ log.Notice("notice")
42
+ log.Warning("warning")
43
+ log.Error("err")
44
+ log.Critical("crit")
45
+ }
46
+}
Godeps/_workspace/src/github.com/op/go-logging/examples/example.png
Binary files /dev/null and b/Godeps/_workspace/src/github.com/op/go-logging/examples/example.png differ
Godeps/_workspace/src/github.com/op/go-logging/format.go
new
+349
@@ -0,0 +1,349 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+import (
8
+ "bytes"
9
+ "errors"
10
+ "fmt"
11
+ "io"
12
+ "os"
13
+ "path"
14
+ "path/filepath"
15
+ "regexp"
16
+ "runtime"
17
+ "strings"
18
+ "sync"
19
+ "time"
20
+)
21
+
22
+// TODO see Formatter interface in fmt/print.go
23
+// TODO try text/template, maybe it have enough performance
24
+// TODO other template systems?
25
+// TODO make it possible to specify formats per backend?
26
+type fmtVerb int
27
+
28
+const (
29
+ fmtVerbTime fmtVerb = iota
30
+ fmtVerbLevel
31
+ fmtVerbId
32
+ fmtVerbPid
33
+ fmtVerbProgram
34
+ fmtVerbModule
35
+ fmtVerbMessage
36
+ fmtVerbLongfile
37
+ fmtVerbShortfile
38
+ fmtVerbLongpkg
39
+ fmtVerbShortpkg
40
+ fmtVerbLongfunc
41
+ fmtVerbShortfunc
42
+ fmtVerbLevelColor
43
+
44
+ // Keep last, there are no match for these below.
45
+ fmtVerbUnknown
46
+ fmtVerbStatic
47
+)
48
+
49
+var fmtVerbs = []string{
50
+ "time",
51
+ "level",
52
+ "id",
53
+ "pid",
54
+ "program",
55
+ "module",
56
+ "message",
57
+ "longfile",
58
+ "shortfile",
59
+ "longpkg",
60
+ "shortpkg",
61
+ "longfunc",
62
+ "shortfunc",
63
+ "color",
64
+}
65
+
66
+const rfc3339Milli = "2006-01-02T15:04:05.999Z07:00"
67
+
68
+var defaultVerbsLayout = []string{
69
+ rfc3339Milli,
70
+ "s",
71
+ "d",
72
+ "d",
73
+ "s",
74
+ "s",
75
+ "s",
76
+ "s",
77
+ "s",
78
+ "s",
79
+ "s",
80
+ "s",
81
+ "s",
82
+ "",
83
+}
84
+
85
+var (
86
+ pid = os.Getpid()
87
+ program = filepath.Base(os.Args[0])
88
+)
89
+
90
+func getFmtVerbByName(name string) fmtVerb {
91
+ for i, verb := range fmtVerbs {
92
+ if name == verb {
93
+ return fmtVerb(i)
94
+ }
95
+ }
96
+ return fmtVerbUnknown
97
+}
98
+
99
+// Formatter is the required interface for a custom log record formatter.
100
+type Formatter interface {
101
+ Format(calldepth int, r *Record, w io.Writer) error
102
+}
103
+
104
+// formatter is used by all backends unless otherwise overriden.
105
+var formatter struct {
106
+ sync.RWMutex
107
+ def Formatter
108
+}
109
+
110
+func getFormatter() Formatter {
111
+ formatter.RLock()
112
+ defer formatter.RUnlock()
113
+ return formatter.def
114
+}
115
+
116
+var (
117
+ // DefaultFormatter is the default formatter used and is only the message.
118
+ DefaultFormatter Formatter = MustStringFormatter("%{message}")
119
+
120
+ // Glog format
121
+ GlogFormatter Formatter = MustStringFormatter("%{level:.1s}%{time:0102 15:04:05.999999} %{pid} %{shortfile}] %{message}")
122
+)
123
+
124
+// SetFormatter sets the default formatter for all new backends. A backend will
125
+// fetch this value once it is needed to format a record. Note that backends
126
+// will cache the formatter after the first point. For now, make sure to set
127
+// the formatter before logging.
128
+func SetFormatter(f Formatter) {
129
+ formatter.Lock()
130
+ defer formatter.Unlock()
131
+ formatter.def = f
132
+}
133
+
134
+var formatRe *regexp.Regexp = regexp.MustCompile(`%{([a-z]+)(?::(.*?[^\\]))?}`)
135
+
136
+type part struct {
137
+ verb fmtVerb
138
+ layout string
139
+}
140
+
141
+// stringFormatter contains a list of parts which explains how to build the
142
+// formatted string passed on to the logging backend.
143
+type stringFormatter struct {
144
+ parts []part
145
+}
146
+
147
+// NewStringFormatter returns a new Formatter which outputs the log record as a
148
+// string based on the 'verbs' specified in the format string.
149
+//
150
+// The verbs:
151
+//
152
+// General:
153
+// %{id} Sequence number for log message (uint64).
154
+// %{pid} Process id (int)
155
+// %{time} Time when log occurred (time.Time)
156
+// %{level} Log level (Level)
157
+// %{module} Module (string)
158
+// %{program} Basename of os.Args[0] (string)
159
+// %{message} Message (string)
160
+// %{longfile} Full file name and line number: /a/b/c/d.go:23
161
+// %{shortfile} Final file name element and line number: d.go:23
162
+// %{color} ANSI color based on log level
163
+//
164
+// For normal types, the output can be customized by using the 'verbs' defined
165
+// in the fmt package, eg. '%{id:04d}' to make the id output be '%04d' as the
166
+// format string.
167
+//
168
+// For time.Time, use the same layout as time.Format to change the time format
169
+// when output, eg "2006-01-02T15:04:05.999Z-07:00".
170
+//
171
+// For the 'color' verb, the output can be adjusted to either use bold colors,
172
+// i.e., '%{color:bold}' or to reset the ANSI attributes, i.e.,
173
+// '%{color:reset}' Note that if you use the color verb explicitly, be sure to
174
+// reset it or else the color state will persist past your log message. e.g.,
175
+// "%{color:bold}%{time:15:04:05} %{level:-8s}%{color:reset} %{message}" will
176
+// just colorize the time and level, leaving the message uncolored.
177
+//
178
+// There's also a couple of experimental 'verbs'. These are exposed to get
179
+// feedback and needs a bit of tinkering. Hence, they might change in the
180
+// future.
181
+//
182
+// Experimental:
183
+// %{longpkg} Full package path, eg. github.com/go-logging
184
+// %{shortpkg} Base package path, eg. go-logging
185
+// %{longfunc} Full function name, eg. littleEndian.PutUint32
186
+// %{shortfunc} Base function name, eg. PutUint32
187
+func NewStringFormatter(format string) (*stringFormatter, error) {
188
+ var fmter = &stringFormatter{}
189
+
190
+ // Find the boundaries of all %{vars}
191
+ matches := formatRe.FindAllStringSubmatchIndex(format, -1)
192
+ if matches == nil {
193
+ return nil, errors.New("logger: invalid log format: " + format)
194
+ }
195
+
196
+ // Collect all variables and static text for the format
197
+ prev := 0
198
+ for _, m := range matches {
199
+ start, end := m[0], m[1]
200
+ if start > prev {
201
+ fmter.add(fmtVerbStatic, format[prev:start])
202
+ }
203
+
204
+ name := format[m[2]:m[3]]
205
+ verb := getFmtVerbByName(name)
206
+ if verb == fmtVerbUnknown {
207
+ return nil, errors.New("logger: unknown variable: " + name)
208
+ }
209
+
210
+ // Handle layout customizations or use the default. If this is not for the
211
+ // time or color formatting, we need to prefix with %.
212
+ layout := defaultVerbsLayout[verb]
213
+ if m[4] != -1 {
214
+ layout = format[m[4]:m[5]]
215
+ }
216
+ if verb != fmtVerbTime && verb != fmtVerbLevelColor {
217
+ layout = "%" + layout
218
+ }
219
+
220
+ fmter.add(verb, layout)
221
+ prev = end
222
+ }
223
+ end := format[prev:]
224
+ if end != "" {
225
+ fmter.add(fmtVerbStatic, end)
226
+ }
227
+
228
+ // Make a test run to make sure we can format it correctly.
229
+ t, err := time.Parse(time.RFC3339, "2010-02-04T21:00:57-08:00")
230
+ if err != nil {
231
+ panic(err)
232
+ }
233
+ r := &Record{
234
+ Id: 12345,
235
+ Time: t,
236
+ Module: "logger",
237
+ fmt: "hello %s",
238
+ args: []interface{}{"go"},
239
+ }
240
+ if err := fmter.Format(0, r, &bytes.Buffer{}); err != nil {
241
+ return nil, err
242
+ }
243
+
244
+ formatter.def = fmter
245
+
246
+ return fmter, nil
247
+}
248
+
249
+// MustStringFormatter is equivalent to NewStringFormatter with a call to panic
250
+// on error.
251
+func MustStringFormatter(format string) *stringFormatter {
252
+ f, err := NewStringFormatter(format)
253
+ if err != nil {
254
+ panic("Failed to initialized string formatter: " + err.Error())
255
+ }
256
+ return f
257
+}
258
+
259
+func (f *stringFormatter) add(verb fmtVerb, layout string) {
260
+ f.parts = append(f.parts, part{verb, layout})
261
+}
262
+
263
+func (f *stringFormatter) Format(calldepth int, r *Record, output io.Writer) error {
264
+ for _, part := range f.parts {
265
+ if part.verb == fmtVerbStatic {
266
+ output.Write([]byte(part.layout))
267
+ } else if part.verb == fmtVerbTime {
268
+ output.Write([]byte(r.Time.Format(part.layout)))
269
+ } else if part.verb == fmtVerbLevelColor {
270
+ if part.layout == "bold" {
271
+ output.Write([]byte(boldcolors[r.Level]))
272
+ } else if part.layout == "reset" {
273
+ output.Write([]byte("\033[0m"))
274
+ } else {
275
+ output.Write([]byte(colors[r.Level]))
276
+ }
277
+ } else {
278
+ var v interface{}
279
+ switch part.verb {
280
+ case fmtVerbLevel:
281
+ v = r.Level
282
+ break
283
+ case fmtVerbId:
284
+ v = r.Id
285
+ break
286
+ case fmtVerbPid:
287
+ v = pid
288
+ break
289
+ case fmtVerbProgram:
290
+ v = program
291
+ break
292
+ case fmtVerbModule:
293
+ v = r.Module
294
+ break
295
+ case fmtVerbMessage:
296
+ v = r.Message()
297
+ break
298
+ case fmtVerbLongfile, fmtVerbShortfile:
299
+ _, file, line, ok := runtime.Caller(calldepth + 1)
300
+ if !ok {
301
+ file = "???"
302
+ line = 0
303
+ } else if part.verb == fmtVerbShortfile {
304
+ file = filepath.Base(file)
305
+ }
306
+ v = fmt.Sprintf("%s:%d", file, line)
307
+ case fmtVerbLongfunc, fmtVerbShortfunc,
308
+ fmtVerbLongpkg, fmtVerbShortpkg:
309
+ // TODO cache pc
310
+ v = "???"
311
+ if pc, _, _, ok := runtime.Caller(calldepth + 1); ok {
312
+ if f := runtime.FuncForPC(pc); f != nil {
313
+ v = formatFuncName(part.verb, f.Name())
314
+ }
315
+ }
316
+ default:
317
+ panic("unhandled format part")
318
+ }
319
+ fmt.Fprintf(output, part.layout, v)
320
+ }
321
+ }
322
+ return nil
323
+}
324
+
325
+// formatFuncName tries to extract certain part of the runtime formatted
326
+// function name to some pre-defined variation.
327
+//
328
+// This function is known to not work properly if the package path or name
329
+// contains a dot.
330
+func formatFuncName(v fmtVerb, f string) string {
331
+ i := strings.LastIndex(f, "/")
332
+ j := strings.Index(f[i+1:], ".")
333
+ if j < 1 {
334
+ return "???"
335
+ }
336
+ pkg, fun := f[:i+j+1], f[i+j+2:]
337
+ switch v {
338
+ case fmtVerbLongpkg:
339
+ return pkg
340
+ case fmtVerbShortpkg:
341
+ return path.Base(pkg)
342
+ case fmtVerbLongfunc:
343
+ return fun
344
+ case fmtVerbShortfunc:
345
+ i = strings.LastIndex(fun, ".")
346
+ return fun[i+1:]
347
+ }
348
+ panic("unexpected func formatter")
349
+}
Godeps/_workspace/src/github.com/op/go-logging/format_test.go
new
+158
@@ -0,0 +1,158 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+import (
8
+ "bytes"
9
+ "testing"
10
+)
11
+
12
+func TestFormat(t *testing.T) {
13
+ backend := InitForTesting(DEBUG)
14
+
15
+ f, err := NewStringFormatter("%{shortfile} %{time:2006-01-02T15:04:05} %{level:.1s} %{id:04d} %{module} %{message}")
16
+ if err != nil {
17
+ t.Fatalf("failed to set format: %s", err)
18
+ }
19
+ SetFormatter(f)
20
+
21
+ log := MustGetLogger("module")
22
+ log.Debug("hello")
23
+
24
+ line := MemoryRecordN(backend, 0).Formatted(0)
25
+ if "format_test.go:24 1970-01-01T00:00:00 D 0001 module hello" != line {
26
+ t.Errorf("Unexpected format: %s", line)
27
+ }
28
+}
29
+
30
+func logAndGetLine(backend *MemoryBackend) string {
31
+ MustGetLogger("foo").Debug("hello")
32
+ return MemoryRecordN(backend, 0).Formatted(1)
33
+}
34
+
35
+func realFunc(backend *MemoryBackend) string {
36
+ return logAndGetLine(backend)
37
+}
38
+
39
+type structFunc struct{}
40
+
41
+func (structFunc) Log(backend *MemoryBackend) string {
42
+ return logAndGetLine(backend)
43
+}
44
+
45
+func TestRealFuncFormat(t *testing.T) {
46
+ backend := InitForTesting(DEBUG)
47
+ SetFormatter(MustStringFormatter("%{shortfunc}"))
48
+
49
+ line := realFunc(backend)
50
+ if "realFunc" != line {
51
+ t.Errorf("Unexpected format: %s", line)
52
+ }
53
+}
54
+
55
+func TestStructFuncFormat(t *testing.T) {
56
+ backend := InitForTesting(DEBUG)
57
+ SetFormatter(MustStringFormatter("%{longfunc}"))
58
+
59
+ var x structFunc
60
+ line := x.Log(backend)
61
+ if "structFunc.Log" != line {
62
+ t.Errorf("Unexpected format: %s", line)
63
+ }
64
+}
65
+
66
+func TestVarFuncFormat(t *testing.T) {
67
+ backend := InitForTesting(DEBUG)
68
+ SetFormatter(MustStringFormatter("%{shortfunc}"))
69
+
70
+ var varFunc = func() string {
71
+ return logAndGetLine(backend)
72
+ }
73
+
74
+ line := varFunc()
75
+ if "???" == line || "TestVarFuncFormat" == line || "varFunc" == line {
76
+ t.Errorf("Unexpected format: %s", line)
77
+ }
78
+}
79
+
80
+func TestFormatFuncName(t *testing.T) {
81
+ var tests = []struct {
82
+ filename string
83
+ longpkg string
84
+ shortpkg string
85
+ longfunc string
86
+ shortfunc string
87
+ }{
88
+ {"",
89
+ "???",
90
+ "???",
91
+ "???",
92
+ "???"},
93
+ {"main",
94
+ "???",
95
+ "???",
96
+ "???",
97
+ "???"},
98
+ {"main.",
99
+ "main",
100
+ "main",
101
+ "",
102
+ ""},
103
+ {"main.main",
104
+ "main",
105
+ "main",
106
+ "main",
107
+ "main"},
108
+ {"github.com/op/go-logging.func·001",
109
+ "github.com/op/go-logging",
110
+ "go-logging",
111
+ "func·001",
112
+ "func·001"},
113
+ {"github.com/op/go-logging.stringFormatter.Format",
114
+ "github.com/op/go-logging",
115
+ "go-logging",
116
+ "stringFormatter.Format",
117
+ "Format"},
118
+ }
119
+
120
+ var v string
121
+ for _, test := range tests {
122
+ v = formatFuncName(fmtVerbLongpkg, test.filename)
123
+ if test.longpkg != v {
124
+ t.Errorf("%s != %s", test.longpkg, v)
125
+ }
126
+ v = formatFuncName(fmtVerbShortpkg, test.filename)
127
+ if test.shortpkg != v {
128
+ t.Errorf("%s != %s", test.shortpkg, v)
129
+ }
130
+ v = formatFuncName(fmtVerbLongfunc, test.filename)
131
+ if test.longfunc != v {
132
+ t.Errorf("%s != %s", test.longfunc, v)
133
+ }
134
+ v = formatFuncName(fmtVerbShortfunc, test.filename)
135
+ if test.shortfunc != v {
136
+ t.Errorf("%s != %s", test.shortfunc, v)
137
+ }
138
+ }
139
+}
140
+
141
+func BenchmarkStringFormatter(b *testing.B) {
142
+ fmt := "%{time:2006-01-02T15:04:05} %{level:.1s} %{id:04d} %{module} %{message}"
143
+ f := MustStringFormatter(fmt)
144
+
145
+ backend := InitForTesting(DEBUG)
146
+ buf := &bytes.Buffer{}
147
+ log := MustGetLogger("module")
148
+ log.Debug("")
149
+ record := MemoryRecordN(backend, 0)
150
+
151
+ b.ResetTimer()
152
+ for i := 0; i < b.N; i++ {
153
+ if err := f.Format(1, record, buf); err != nil {
154
+ b.Fatal(err)
155
+ buf.Truncate(0)
156
+ }
157
+ }
158
+}
Godeps/_workspace/src/github.com/op/go-logging/level.go
new
+123
@@ -0,0 +1,123 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+import (
8
+ "errors"
9
+ "strings"
10
+ "sync"
11
+)
12
+
13
+var ErrInvalidLogLevel = errors.New("logger: invalid log level")
14
+
15
+// Level defines all available log levels for log messages.
16
+type Level int
17
+
18
+const (
19
+ CRITICAL Level = iota
20
+ ERROR
21
+ WARNING
22
+ NOTICE
23
+ INFO
24
+ DEBUG
25
+)
26
+
27
+var levelNames = []string{
28
+ "CRITICAL",
29
+ "ERROR",
30
+ "WARNING",
31
+ "NOTICE",
32
+ "INFO",
33
+ "DEBUG",
34
+}
35
+
36
+// String returns the string representation of a logging level.
37
+func (p Level) String() string {
38
+ return levelNames[p]
39
+}
40
+
41
+// LogLevel returns the log level from a string representation.
42
+func LogLevel(level string) (Level, error) {
43
+ for i, name := range levelNames {
44
+ if strings.EqualFold(name, level) {
45
+ return Level(i), nil
46
+ }
47
+ }
48
+ return ERROR, ErrInvalidLogLevel
49
+}
50
+
51
+type Leveled interface {
52
+ GetLevel(string) Level
53
+ SetLevel(Level, string)
54
+ IsEnabledFor(Level, string) bool
55
+}
56
+
57
+// LeveledBackend is a log backend with additional knobs for setting levels on
58
+// individual modules to different levels.
59
+type LeveledBackend interface {
60
+ Backend
61
+ Leveled
62
+}
63
+
64
+type moduleLeveled struct {
65
+ levels map[string]Level
66
+ backend Backend
67
+ formatter Formatter
68
+ once sync.Once
69
+}
70
+
71
+// AddModuleLevel wraps a log backend with knobs to have different log levels
72
+// for different modules.
73
+func AddModuleLevel(backend Backend) LeveledBackend {
74
+ var leveled LeveledBackend
75
+ var ok bool
76
+ if leveled, ok = backend.(LeveledBackend); !ok {
77
+ leveled = &moduleLeveled{
78
+ levels: make(map[string]Level),
79
+ backend: backend,
80
+ }
81
+ }
82
+ return leveled
83
+}
84
+
85
+// GetLevel returns the log level for the given module.
86
+func (l *moduleLeveled) GetLevel(module string) Level {
87
+ level, exists := l.levels[module]
88
+ if exists == false {
89
+ level, exists = l.levels[""]
90
+ // no configuration exists, default to debug
91
+ if exists == false {
92
+ level = DEBUG
93
+ }
94
+ }
95
+ return level
96
+}
97
+
98
+// SetLevel sets the log level for the given module.
99
+func (l *moduleLeveled) SetLevel(level Level, module string) {
100
+ l.levels[module] = level
101
+}
102
+
103
+// IsEnabledFor will return true if logging is enabled for the given module.
104
+func (l *moduleLeveled) IsEnabledFor(level Level, module string) bool {
105
+ return level <= l.GetLevel(module)
106
+}
107
+
108
+func (l *moduleLeveled) Log(level Level, calldepth int, rec *Record) (err error) {
109
+ if l.IsEnabledFor(level, rec.Module) {
110
+ rec.formatter = l.getFormatterAndCacheCurrent()
111
+ err = l.backend.Log(level, calldepth+1, rec)
112
+ }
113
+ return
114
+}
115
+
116
+func (l *moduleLeveled) getFormatterAndCacheCurrent() Formatter {
117
+ l.once.Do(func() {
118
+ if l.formatter == nil {
119
+ l.formatter = getFormatter()
120
+ }
121
+ })
122
+ return l.formatter
123
+}
Godeps/_workspace/src/github.com/op/go-logging/level_test.go
new
+76
@@ -0,0 +1,76 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+import "testing"
8
+
9
+func TestLevelString(t *testing.T) {
10
+ // Make sure all levels can be converted from string -> constant -> string
11
+ for _, name := range levelNames {
12
+ level, err := LogLevel(name)
13
+ if err != nil {
14
+ t.Errorf("failed to get level: %v", err)
15
+ continue
16
+ }
17
+
18
+ if level.String() != name {
19
+ t.Errorf("invalid level conversion: %v != %v", level, name)
20
+ }
21
+ }
22
+}
23
+
24
+func TestLevelLogLevel(t *testing.T) {
25
+ tests := []struct {
26
+ expected Level
27
+ level string
28
+ }{
29
+ {-1, "bla"},
30
+ {INFO, "iNfO"},
31
+ {ERROR, "error"},
32
+ {WARNING, "warninG"},
33
+ }
34
+
35
+ for _, test := range tests {
36
+ level, err := LogLevel(test.level)
37
+ if err != nil {
38
+ if test.expected == -1 {
39
+ continue
40
+ } else {
41
+ t.Errorf("failed to convert %s: %s", test.level, err)
42
+ }
43
+ }
44
+ if test.expected != level {
45
+ t.Errorf("failed to convert %s to level: %s != %s", test.level, test.expected, level)
46
+ }
47
+ }
48
+}
49
+
50
+func TestLevelModuleLevel(t *testing.T) {
51
+ backend := NewMemoryBackend(128)
52
+
53
+ leveled := AddModuleLevel(backend)
54
+ leveled.SetLevel(NOTICE, "")
55
+ leveled.SetLevel(ERROR, "foo")
56
+ leveled.SetLevel(INFO, "foo.bar")
57
+ leveled.SetLevel(WARNING, "bar")
58
+
59
+ expected := []struct {
60
+ level Level
61
+ module string
62
+ }{
63
+ {NOTICE, ""},
64
+ {NOTICE, "something"},
65
+ {ERROR, "foo"},
66
+ {INFO, "foo.bar"},
67
+ {WARNING, "bar"},
68
+ }
69
+
70
+ for _, e := range expected {
71
+ actual := leveled.GetLevel(e.module)
72
+ if e.level != actual {
73
+ t.Errorf("unexpected level in %s: %s != %s", e.module, e.level, actual)
74
+ }
75
+ }
76
+}
Godeps/_workspace/src/github.com/op/go-logging/log.go
new
+80
@@ -0,0 +1,80 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+import (
8
+ "bytes"
9
+ "fmt"
10
+ "io"
11
+ "log"
12
+)
13
+
14
+// TODO initialize here
15
+var colors []string
16
+var boldcolors []string
17
+
18
+type color int
19
+
20
+const (
21
+ colorBlack = (iota + 30)
22
+ colorRed
23
+ colorGreen
24
+ colorYellow
25
+ colorBlue
26
+ colorMagenta
27
+ colorCyan
28
+ colorWhite
29
+)
30
+
31
+// LogBackend utilizes the standard log module.
32
+type LogBackend struct {
33
+ Logger *log.Logger
34
+ Color bool
35
+}
36
+
37
+// NewLogBackend creates a new LogBackend.
38
+func NewLogBackend(out io.Writer, prefix string, flag int) *LogBackend {
39
+ return &LogBackend{Logger: log.New(out, prefix, flag)}
40
+}
41
+
42
+func (b *LogBackend) Log(level Level, calldepth int, rec *Record) error {
43
+ if b.Color {
44
+ buf := &bytes.Buffer{}
45
+ buf.Write([]byte(colors[level]))
46
+ buf.Write([]byte(rec.Formatted(calldepth + 1)))
47
+ buf.Write([]byte("\033[0m"))
48
+ // For some reason, the Go logger arbitrarily decided "2" was the correct
49
+ // call depth...
50
+ return b.Logger.Output(calldepth+2, buf.String())
51
+ } else {
52
+ return b.Logger.Output(calldepth+2, rec.Formatted(calldepth+1))
53
+ }
54
+ panic("should not be reached")
55
+}
56
+
57
+func colorSeq(color color) string {
58
+ return fmt.Sprintf("\033[%dm", int(color))
59
+}
60
+
61
+func colorSeqBold(color color) string {
62
+ return fmt.Sprintf("\033[%d;1m", int(color))
63
+}
64
+
65
+func init() {
66
+ colors = []string{
67
+ CRITICAL: colorSeq(colorMagenta),
68
+ ERROR: colorSeq(colorRed),
69
+ WARNING: colorSeq(colorYellow),
70
+ NOTICE: colorSeq(colorGreen),
71
+ DEBUG: colorSeq(colorCyan),
72
+ }
73
+ boldcolors = []string{
74
+ CRITICAL: colorSeqBold(colorMagenta),
75
+ ERROR: colorSeqBold(colorRed),
76
+ WARNING: colorSeqBold(colorYellow),
77
+ NOTICE: colorSeqBold(colorGreen),
78
+ DEBUG: colorSeqBold(colorCyan),
79
+ }
80
+}
Godeps/_workspace/src/github.com/op/go-logging/log_test.go
new
+95
@@ -0,0 +1,95 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+import (
8
+ "bytes"
9
+ "log"
10
+ "strings"
11
+ "testing"
12
+)
13
+
14
+func TestLogCalldepth(t *testing.T) {
15
+ buf := &bytes.Buffer{}
16
+ SetBackend(NewLogBackend(buf, "", log.Lshortfile))
17
+ SetFormatter(MustStringFormatter("%{shortfile} %{level} %{message}"))
18
+
19
+ log := MustGetLogger("test")
20
+ log.Info("test filename")
21
+
22
+ parts := strings.SplitN(buf.String(), " ", 2)
23
+
24
+ // Verify that the correct filename is registered by the stdlib logger
25
+ if !strings.HasPrefix(parts[0], "log_test.go:") {
26
+ t.Errorf("incorrect filename: %s", parts[0])
27
+ }
28
+ // Verify that the correct filename is registered by go-logging
29
+ if !strings.HasPrefix(parts[1], "log_test.go:") {
30
+ t.Errorf("incorrect filename: %s", parts[1])
31
+ }
32
+}
33
+
34
+func BenchmarkLogMemoryBackendIgnored(b *testing.B) {
35
+ b.StopTimer()
36
+ backend := SetBackend(NewMemoryBackend(1024))
37
+ backend.SetLevel(INFO, "")
38
+ RunLogBenchmark(b)
39
+}
40
+
41
+func BenchmarkLogMemoryBackend(b *testing.B) {
42
+ b.StopTimer()
43
+ backend := SetBackend(NewMemoryBackend(1024))
44
+ backend.SetLevel(DEBUG, "")
45
+ RunLogBenchmark(b)
46
+}
47
+
48
+func BenchmarkLogChannelMemoryBackend(b *testing.B) {
49
+ b.StopTimer()
50
+ channelBackend := NewChannelMemoryBackend(1024)
51
+ backend := SetBackend(channelBackend)
52
+ backend.SetLevel(DEBUG, "")
53
+ RunLogBenchmark(b)
54
+ channelBackend.Flush()
55
+}
56
+
57
+func BenchmarkLogLogBackend(b *testing.B) {
58
+ b.StopTimer()
59
+ backend := SetBackend(NewLogBackend(&bytes.Buffer{}, "", 0))
60
+ backend.SetLevel(DEBUG, "")
61
+ RunLogBenchmark(b)
62
+}
63
+
64
+func BenchmarkLogLogBackendColor(b *testing.B) {
65
+ b.StopTimer()
66
+ colorizer := NewLogBackend(&bytes.Buffer{}, "", 0)
67
+ colorizer.Color = true
68
+ backend := SetBackend(colorizer)
69
+ backend.SetLevel(DEBUG, "")
70
+ RunLogBenchmark(b)
71
+}
72
+
73
+func BenchmarkLogLogBackendStdFlags(b *testing.B) {
74
+ b.StopTimer()
75
+ backend := SetBackend(NewLogBackend(&bytes.Buffer{}, "", log.LstdFlags))
76
+ backend.SetLevel(DEBUG, "")
77
+ RunLogBenchmark(b)
78
+}
79
+
80
+func BenchmarkLogLogBackendLongFileFlag(b *testing.B) {
81
+ b.StopTimer()
82
+ backend := SetBackend(NewLogBackend(&bytes.Buffer{}, "", log.Llongfile))
83
+ backend.SetLevel(DEBUG, "")
84
+ RunLogBenchmark(b)
85
+}
86
+
87
+func RunLogBenchmark(b *testing.B) {
88
+ password := Password("foo")
89
+ log := MustGetLogger("test")
90
+
91
+ b.StartTimer()
92
+ for i := 0; i < b.N; i++ {
93
+ log.Debug("log line for %d and this is rectified: %s", i, password)
94
+ }
95
+}
Godeps/_workspace/src/github.com/op/go-logging/logger.go
new
+213
@@ -0,0 +1,213 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+// Package logging implements a logging infrastructure for Go. It supports
6
+// different logging backends like syslog, file and memory. Multiple backends
7
+// can be utilized with different log levels per backend and logger.
8
+package logging
9
+
10
+import (
11
+ "bytes"
12
+ "fmt"
13
+ "log"
14
+ "os"
15
+ "strings"
16
+ "sync/atomic"
17
+ "time"
18
+)
19
+
20
+// Redactor is an interface for types that may contain sensitive information
21
+// (like passwords), which shouldn't be printed to the log. The idea was found
22
+// in relog as part of the vitness project.
23
+type Redactor interface {
24
+ Redacted() interface{}
25
+}
26
+
27
+// Redact returns a string of * having the same length as s.
28
+func Redact(s string) string {
29
+ return strings.Repeat("*", len(s))
30
+}
31
+
32
+var (
33
+ // Sequence number is incremented and utilized for all log records created.
34
+ sequenceNo uint64
35
+
36
+ // timeNow is a customizable for testing purposes.
37
+ timeNow = time.Now
38
+)
39
+
40
+// Record represents a log record and contains the timestamp when the record
41
+// was created, an increasing id, filename and line and finally the actual
42
+// formatted log line.
43
+type Record struct {
44
+ Id uint64
45
+ Time time.Time
46
+ Module string
47
+ Level Level
48
+
49
+ // message is kept as a pointer to have shallow copies update this once
50
+ // needed.
51
+ message *string
52
+ args []interface{}
53
+ fmt string
54
+ formatter Formatter
55
+ formatted string
56
+}
57
+
58
+func (r *Record) Formatted(calldepth int) string {
59
+ if r.formatted == "" {
60
+ var buf bytes.Buffer
61
+ r.formatter.Format(calldepth+1, r, &buf)
62
+ r.formatted = buf.String()
63
+ }
64
+ return r.formatted
65
+}
66
+
67
+func (r *Record) Message() string {
68
+ if r.message == nil {
69
+ // Redact the arguments that implements the Redactor interface
70
+ for i, arg := range r.args {
71
+ if redactor, ok := arg.(Redactor); ok == true {
72
+ r.args[i] = redactor.Redacted()
73
+ }
74
+ }
75
+ msg := fmt.Sprintf(r.fmt, r.args...)
76
+ r.message = &msg
77
+ }
78
+ return *r.message
79
+}
80
+
81
+type Logger struct {
82
+ Module string
83
+}
84
+
85
+// TODO call NewLogger and remove MustGetLogger?
86
+// GetLogger creates and returns a Logger object based on the module name.
87
+func GetLogger(module string) (*Logger, error) {
88
+ return &Logger{Module: module}, nil
89
+}
90
+
91
+// MustGetLogger is like GetLogger but panics if the logger can't be created.
92
+// It simplifies safe initialization of a global logger for eg. a package.
93
+func MustGetLogger(module string) *Logger {
94
+ logger, err := GetLogger(module)
95
+ if err != nil {
96
+ panic("logger: " + module + ": " + err.Error())
97
+ }
98
+ return logger
99
+}
100
+
101
+// Reset restores the internal state of the logging library.
102
+func Reset() {
103
+ // TODO make a global Init() method to be less magic? or make it such that
104
+ // if there's no backends at all configured, we could use some tricks to
105
+ // automatically setup backends based if we have a TTY or not.
106
+ sequenceNo = 0
107
+ b := SetBackend(NewLogBackend(os.Stderr, "", log.LstdFlags))
108
+ b.SetLevel(DEBUG, "")
109
+ SetFormatter(DefaultFormatter)
110
+ timeNow = time.Now
111
+}
112
+
113
+// InitForTesting is a convenient method when using logging in a test. Once
114
+// called, the time will be frozen to January 1, 1970 UTC.
115
+func InitForTesting(level Level) *MemoryBackend {
116
+ Reset()
117
+
118
+ memoryBackend := NewMemoryBackend(10240)
119
+
120
+ leveledBackend := AddModuleLevel(memoryBackend)
121
+ leveledBackend.SetLevel(level, "")
122
+ SetBackend(leveledBackend)
123
+
124
+ timeNow = func() time.Time {
125
+ return time.Unix(0, 0).UTC()
126
+ }
127
+ return memoryBackend
128
+}
129
+
130
+// IsEnabledFor returns true if the logger is enabled for the given level.
131
+func (l *Logger) IsEnabledFor(level Level) bool {
132
+ return defaultBackend.IsEnabledFor(level, l.Module)
133
+}
134
+
135
+func (l *Logger) log(lvl Level, format string, args ...interface{}) {
136
+ // Create the logging record and pass it in to the backend
137
+ record := &Record{
138
+ Id: atomic.AddUint64(&sequenceNo, 1),
139
+ Time: timeNow(),
140
+ Module: l.Module,
141
+ Level: lvl,
142
+ fmt: format,
143
+ args: args,
144
+ }
145
+
146
+ // TODO use channels to fan out the records to all backends?
147
+ // TODO in case of errors, do something (tricky)
148
+
149
+ // calldepth=2 brings the stack up to the caller of the level
150
+ // methods, Info(), Fatal(), etc.
151
+ defaultBackend.Log(lvl, 2, record)
152
+}
153
+
154
+// Fatal is equivalent to l.Critical(fmt.Sprint()) followed by a call to os.Exit(1).
155
+func (l *Logger) Fatal(args ...interface{}) {
156
+ s := fmt.Sprint(args...)
157
+ l.log(CRITICAL, "%s", s)
158
+ os.Exit(1)
159
+}
160
+
161
+// Fatalf is equivalent to l.Critical followed by a call to os.Exit(1).
162
+func (l *Logger) Fatalf(format string, args ...interface{}) {
163
+ l.log(CRITICAL, format, args...)
164
+ os.Exit(1)
165
+}
166
+
167
+// Panic is equivalent to l.Critical(fmt.Sprint()) followed by a call to panic().
168
+func (l *Logger) Panic(args ...interface{}) {
169
+ s := fmt.Sprint(args...)
170
+ l.log(CRITICAL, "%s", s)
171
+ panic(s)
172
+}
173
+
174
+// Panicf is equivalent to l.Critical followed by a call to panic().
175
+func (l *Logger) Panicf(format string, args ...interface{}) {
176
+ s := fmt.Sprintf(format, args...)
177
+ l.log(CRITICAL, "%s", s)
178
+ panic(s)
179
+}
180
+
181
+// Critical logs a message using CRITICAL as log level.
182
+func (l *Logger) Critical(format string, args ...interface{}) {
183
+ l.log(CRITICAL, format, args...)
184
+}
185
+
186
+// Error logs a message using ERROR as log level.
187
+func (l *Logger) Error(format string, args ...interface{}) {
188
+ l.log(ERROR, format, args...)
189
+}
190
+
191
+// Warning logs a message using WARNING as log level.
192
+func (l *Logger) Warning(format string, args ...interface{}) {
193
+ l.log(WARNING, format, args...)
194
+}
195
+
196
+// Notice logs a message using NOTICE as log level.
197
+func (l *Logger) Notice(format string, args ...interface{}) {
198
+ l.log(NOTICE, format, args...)
199
+}
200
+
201
+// Info logs a message using INFO as log level.
202
+func (l *Logger) Info(format string, args ...interface{}) {
203
+ l.log(INFO, format, args...)
204
+}
205
+
206
+// Debug logs a message using DEBUG as log level.
207
+func (l *Logger) Debug(format string, args ...interface{}) {
208
+ l.log(DEBUG, format, args...)
209
+}
210
+
211
+func init() {
212
+ Reset()
213
+}
Godeps/_workspace/src/github.com/op/go-logging/logger_test.go
new
+36
@@ -0,0 +1,36 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+import "testing"
8
+
9
+type Password string
10
+
11
+func (p Password) Redacted() interface{} {
12
+ return Redact(string(p))
13
+}
14
+
15
+func TestSequenceNoOverflow(t *testing.T) {
16
+ // Forcefully set the next sequence number to the maximum
17
+ backend := InitForTesting(DEBUG)
18
+ sequenceNo = ^uint64(0)
19
+
20
+ log := MustGetLogger("test")
21
+ log.Debug("test")
22
+
23
+ if MemoryRecordN(backend, 0).Id != 0 {
24
+ t.Errorf("Unexpected sequence no: %v", MemoryRecordN(backend, 0).Id)
25
+ }
26
+}
27
+
28
+func TestRedact(t *testing.T) {
29
+ backend := InitForTesting(DEBUG)
30
+ password := Password("123456")
31
+ log := MustGetLogger("test")
32
+ log.Debug("foo %s", password)
33
+ if "foo ******" != MemoryRecordN(backend, 0).Formatted(0) {
34
+ t.Errorf("redacted line: %v", MemoryRecordN(backend, 0))
35
+ }
36
+}
Godeps/_workspace/src/github.com/op/go-logging/memory.go
new
+217
@@ -0,0 +1,217 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+import (
8
+ "sync"
9
+ "sync/atomic"
10
+ "unsafe"
11
+)
12
+
13
+// TODO pick one of the memory backends and stick with it or share interface.
14
+
15
+// Node is a record node pointing to an optional next node.
16
+type node struct {
17
+ next *node
18
+ Record *Record
19
+}
20
+
21
+// Next returns the next record node. If there's no node available, it will
22
+// return nil.
23
+func (n *node) Next() *node {
24
+ return n.next
25
+}
26
+
27
+// MemoryBackend is a simple memory based logging backend that will not produce
28
+// any output but merly keep records, up to the given size, in memory.
29
+type MemoryBackend struct {
30
+ size int32
31
+ maxSize int32
32
+ head, tail unsafe.Pointer
33
+}
34
+
35
+// NewMemoryBackend creates a simple in-memory logging backend.
36
+func NewMemoryBackend(size int) *MemoryBackend {
37
+ return &MemoryBackend{maxSize: int32(size)}
38
+}
39
+
40
+// Log implements the Log method required by Backend.
41
+func (b *MemoryBackend) Log(level Level, calldepth int, rec *Record) error {
42
+ var size int32
43
+
44
+ n := &node{Record: rec}
45
+ np := unsafe.Pointer(n)
46
+
47
+ // Add the record to the tail. If there's no records available, tail and
48
+ // head will both be nil. When we successfully set the tail and the previous
49
+ // value was nil, it's safe to set the head to the current value too.
50
+ for {
51
+ tailp := b.tail
52
+ swapped := atomic.CompareAndSwapPointer(
53
+ &b.tail,
54
+ tailp,
55
+ np,
56
+ )
57
+ if swapped == true {
58
+ if tailp == nil {
59
+ b.head = np
60
+ } else {
61
+ (*node)(tailp).next = n
62
+ }
63
+ size = atomic.AddInt32(&b.size, 1)
64
+ break
65
+ }
66
+ }
67
+
68
+ // Since one record was added, we might have overflowed the list. Remove
69
+ // a record if that is the case. The size will fluctate a bit, but
70
+ // eventual consistent.
71
+ if b.maxSize > 0 && size > b.maxSize {
72
+ for {
73
+ headp := b.head
74
+ head := (*node)(b.head)
75
+ if head.next == nil {
76
+ break
77
+ }
78
+ swapped := atomic.CompareAndSwapPointer(
79
+ &b.head,
80
+ headp,
81
+ unsafe.Pointer(head.next),
82
+ )
83
+ if swapped == true {
84
+ atomic.AddInt32(&b.size, -1)
85
+ break
86
+ }
87
+ }
88
+ }
89
+ return nil
90
+}
91
+
92
+// Head returns the oldest record node kept in memory. It can be used to
93
+// iterate over records, one by one, up to the last record.
94
+//
95
+// Note: new records can get added while iterating. Hence the number of records
96
+// iterated over might be larger than the maximum size.
97
+func (b *MemoryBackend) Head() *node {
98
+ return (*node)(b.head)
99
+}
100
+
101
+type event int
102
+
103
+const (
104
+ eventFlush event = iota
105
+ eventStop
106
+)
107
+
108
+// ChannelMemoryBackend is very similar to the MemoryBackend, except that it
109
+// internally utilizes a channel.
110
+type ChannelMemoryBackend struct {
111
+ maxSize int
112
+ size int
113
+ incoming chan *Record
114
+ events chan event
115
+ mu sync.Mutex
116
+ running bool
117
+ flushWg sync.WaitGroup
118
+ stopWg sync.WaitGroup
119
+ head, tail *node
120
+}
121
+
122
+// NewChannelMemoryBackend creates a simple in-memory logging backend which
123
+// utilizes a go channel for communication.
124
+//
125
+// Start will automatically be called by this function.
126
+func NewChannelMemoryBackend(size int) *ChannelMemoryBackend {
127
+ backend := &ChannelMemoryBackend{
128
+ maxSize: size,
129
+ incoming: make(chan *Record, 1024),
130
+ events: make(chan event),
131
+ }
132
+ backend.Start()
133
+ return backend
134
+}
135
+
136
+// Start launches the internal goroutine which starts processing data from the
137
+// input channel.
138
+func (b *ChannelMemoryBackend) Start() {
139
+ b.mu.Lock()
140
+ defer b.mu.Unlock()
141
+
142
+ // Launch the goroutine unless it's already running.
143
+ if b.running != true {
144
+ b.running = true
145
+ b.stopWg.Add(1)
146
+ go b.process()
147
+ }
148
+}
149
+
150
+func (b *ChannelMemoryBackend) process() {
151
+ for {
152
+ select {
153
+ case rec := <-b.incoming:
154
+ b.insertRecord(rec)
155
+ case e := <-b.events:
156
+ switch e {
157
+ case eventStop:
158
+ break
159
+ case eventFlush:
160
+ for len(b.incoming) > 0 {
161
+ b.insertRecord(<-b.incoming)
162
+ }
163
+ b.flushWg.Done()
164
+ }
165
+ }
166
+ }
167
+ b.stopWg.Done()
168
+}
169
+
170
+func (b *ChannelMemoryBackend) insertRecord(rec *Record) {
171
+ prev := b.tail
172
+ b.tail = &node{Record: rec}
173
+ if prev == nil {
174
+ b.head = b.tail
175
+ } else {
176
+ prev.next = b.tail
177
+ }
178
+
179
+ if b.maxSize > 0 && b.size >= b.maxSize {
180
+ b.head = b.head.next
181
+ } else {
182
+ b.size += 1
183
+ }
184
+}
185
+
186
+// Flush waits until all records in the buffered channel have been processed.
187
+func (b *ChannelMemoryBackend) Flush() {
188
+ b.flushWg.Add(1)
189
+ b.events <- eventFlush
190
+ b.flushWg.Wait()
191
+}
192
+
193
+// Stop signals the internal goroutine to exit and waits until it have.
194
+func (b *ChannelMemoryBackend) Stop() {
195
+ b.mu.Lock()
196
+ if b.running == true {
197
+ b.running = false
198
+ b.events <- eventStop
199
+ }
200
+ b.mu.Unlock()
201
+ b.stopWg.Wait()
202
+}
203
+
204
+// Log implements the Log method required by Backend.
205
+func (b *ChannelMemoryBackend) Log(level Level, calldepth int, rec *Record) error {
206
+ b.incoming <- rec
207
+ return nil
208
+}
209
+
210
+// Head returns the oldest record node kept in memory. It can be used to
211
+// iterate over records, one by one, up to the last record.
212
+//
213
+// Note: new records can get added while iterating. Hence the number of records
214
+// iterated over might be larger than the maximum size.
215
+func (b *ChannelMemoryBackend) Head() *node {
216
+ return b.head
217
+}
Godeps/_workspace/src/github.com/op/go-logging/memory_test.go
new
+117
@@ -0,0 +1,117 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+import (
8
+ "strconv"
9
+ "testing"
10
+)
11
+
12
+// TODO share more code between these tests
13
+func MemoryRecordN(b *MemoryBackend, n int) *Record {
14
+ node := b.Head()
15
+ for i := 0; i < n; i++ {
16
+ if node == nil {
17
+ break
18
+ }
19
+ node = node.Next()
20
+ }
21
+ if node == nil {
22
+ return nil
23
+ }
24
+ return node.Record
25
+}
26
+
27
+func ChannelMemoryRecordN(b *ChannelMemoryBackend, n int) *Record {
28
+ b.Flush()
29
+ node := b.Head()
30
+ for i := 0; i < n; i++ {
31
+ if node == nil {
32
+ break
33
+ }
34
+ node = node.Next()
35
+ }
36
+ if node == nil {
37
+ return nil
38
+ }
39
+ return node.Record
40
+}
41
+
42
+func TestMemoryBackend(t *testing.T) {
43
+ backend := NewMemoryBackend(8)
44
+ SetBackend(backend)
45
+
46
+ log := MustGetLogger("test")
47
+
48
+ if nil != MemoryRecordN(backend, 0) || 0 != backend.size {
49
+ t.Errorf("memory level: %d", backend.size)
50
+ }
51
+
52
+ // Run 13 times, the resulting vector should be [5..12]
53
+ for i := 0; i < 13; i++ {
54
+ log.Info("%d", i)
55
+ }
56
+
57
+ if 8 != backend.size {
58
+ t.Errorf("record length: %d", backend.size)
59
+ }
60
+ record := MemoryRecordN(backend, 0)
61
+ if "5" != record.Formatted(0) {
62
+ t.Errorf("unexpected start: %s", record.Formatted(0))
63
+ }
64
+ for i := 0; i < 8; i++ {
65
+ record = MemoryRecordN(backend, i)
66
+ if strconv.Itoa(i+5) != record.Formatted(0) {
67
+ t.Errorf("unexpected record: %v", record.Formatted(0))
68
+ }
69
+ }
70
+ record = MemoryRecordN(backend, 7)
71
+ if "12" != record.Formatted(0) {
72
+ t.Errorf("unexpected end: %s", record.Formatted(0))
73
+ }
74
+ record = MemoryRecordN(backend, 8)
75
+ if nil != record {
76
+ t.Errorf("unexpected eof: %s", record.Formatted(0))
77
+ }
78
+}
79
+
80
+func TestChannelMemoryBackend(t *testing.T) {
81
+ backend := NewChannelMemoryBackend(8)
82
+ SetBackend(backend)
83
+
84
+ log := MustGetLogger("test")
85
+
86
+ if nil != ChannelMemoryRecordN(backend, 0) || 0 != backend.size {
87
+ t.Errorf("memory level: %d", backend.size)
88
+ }
89
+
90
+ // Run 13 times, the resulting vector should be [5..12]
91
+ for i := 0; i < 13; i++ {
92
+ log.Info("%d", i)
93
+ }
94
+ backend.Flush()
95
+
96
+ if 8 != backend.size {
97
+ t.Errorf("record length: %d", backend.size)
98
+ }
99
+ record := ChannelMemoryRecordN(backend, 0)
100
+ if "5" != record.Formatted(0) {
101
+ t.Errorf("unexpected start: %s", record.Formatted(0))
102
+ }
103
+ for i := 0; i < 8; i++ {
104
+ record = ChannelMemoryRecordN(backend, i)
105
+ if strconv.Itoa(i+5) != record.Formatted(0) {
106
+ t.Errorf("unexpected record: %v", record.Formatted(0))
107
+ }
108
+ }
109
+ record = ChannelMemoryRecordN(backend, 7)
110
+ if "12" != record.Formatted(0) {
111
+ t.Errorf("unexpected end: %s", record.Formatted(0))
112
+ }
113
+ record = ChannelMemoryRecordN(backend, 8)
114
+ if nil != record {
115
+ t.Errorf("unexpected eof: %s", record.Formatted(0))
116
+ }
117
+}
Godeps/_workspace/src/github.com/op/go-logging/multi.go
new
+63
@@ -0,0 +1,63 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+// multiLogger is a log multiplexer which can be used to utilize multiple log
8
+// backends at once.
9
+type multiLogger struct {
10
+ backends []LeveledBackend
11
+}
12
+
13
+// MultiLogger creates a logger which contain multiple loggers.
14
+func MultiLogger(backends ...Backend) LeveledBackend {
15
+ var leveledBackends []LeveledBackend
16
+ for _, backend := range backends {
17
+ leveledBackends = append(leveledBackends, AddModuleLevel(backend))
18
+ }
19
+ return &multiLogger{leveledBackends}
20
+}
21
+
22
+// Log passes the log record to all backends.
23
+func (b *multiLogger) Log(level Level, calldepth int, rec *Record) (err error) {
24
+ for _, backend := range b.backends {
25
+ if backend.IsEnabledFor(level, rec.Module) {
26
+ // Shallow copy of the record for the formatted cache on Record and get the
27
+ // record formatter from the backend.
28
+ r2 := *rec
29
+ if e := backend.Log(level, calldepth+1, &r2); e != nil {
30
+ err = e
31
+ }
32
+ }
33
+ }
34
+ return
35
+}
36
+
37
+// GetLevel returns the highest level enabled by all backends.
38
+func (b *multiLogger) GetLevel(module string) Level {
39
+ var level Level
40
+ for _, backend := range b.backends {
41
+ if backendLevel := backend.GetLevel(module); backendLevel > level {
42
+ level = backendLevel
43
+ }
44
+ }
45
+ return level
46
+}
47
+
48
+// SetLevel propagates the same level to all backends.
49
+func (b *multiLogger) SetLevel(level Level, module string) {
50
+ for _, backend := range b.backends {
51
+ backend.SetLevel(level, module)
52
+ }
53
+}
54
+
55
+// IsEnabledFor returns true if any of the backends are enabled for it.
56
+func (b *multiLogger) IsEnabledFor(level Level, module string) bool {
57
+ for _, backend := range b.backends {
58
+ if backend.IsEnabledFor(level, module) {
59
+ return true
60
+ }
61
+ }
62
+ return false
63
+}
Godeps/_workspace/src/github.com/op/go-logging/multi_test.go
new
+51
@@ -0,0 +1,51 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package logging
6
+
7
+import "testing"
8
+
9
+func TestMultiLogger(t *testing.T) {
10
+ log1 := NewMemoryBackend(8)
11
+ log2 := NewMemoryBackend(8)
12
+ SetBackend(MultiLogger(log1, log2))
13
+
14
+ log := MustGetLogger("test")
15
+ log.Debug("log")
16
+
17
+ if "log" != MemoryRecordN(log1, 0).Formatted(0) {
18
+ t.Errorf("log1: %v", MemoryRecordN(log1, 0).Formatted(0))
19
+ }
20
+ if "log" != MemoryRecordN(log2, 0).Formatted(0) {
21
+ t.Errorf("log2: %v", MemoryRecordN(log2, 0).Formatted(0))
22
+ }
23
+}
24
+
25
+func TestMultiLoggerLevel(t *testing.T) {
26
+ log1 := NewMemoryBackend(8)
27
+ log2 := NewMemoryBackend(8)
28
+
29
+ leveled1 := AddModuleLevel(log1)
30
+ leveled2 := AddModuleLevel(log2)
31
+
32
+ multi := MultiLogger(leveled1, leveled2)
33
+ multi.SetLevel(ERROR, "test")
34
+ SetBackend(multi)
35
+
36
+ log := MustGetLogger("test")
37
+ log.Notice("log")
38
+
39
+ if nil != MemoryRecordN(log1, 0) || nil != MemoryRecordN(log2, 0) {
40
+ t.Errorf("unexpected log record")
41
+ }
42
+
43
+ leveled1.SetLevel(DEBUG, "test")
44
+ log.Notice("log")
45
+ if "log" != MemoryRecordN(log1, 0).Formatted(0) {
46
+ t.Errorf("log1 not receieved")
47
+ }
48
+ if nil != MemoryRecordN(log2, 0) {
49
+ t.Errorf("log2 receieved")
50
+ }
51
+}
Godeps/_workspace/src/github.com/op/go-logging/syslog.go
new
+52
@@ -0,0 +1,52 @@
1
+// Copyright 2013, Örjan Persson. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+//+build !windows,!plan9
6
+
7
+package logging
8
+
9
+import "log/syslog"
10
+
11
+// SyslogBackend is a simple logger to syslog backend. It automatically maps
12
+// the internal log levels to appropriate syslog log levels.
13
+type SyslogBackend struct {
14
+ Writer *syslog.Writer
15
+}
16
+
17
+// NewSyslogBackend connects to the syslog daemon using UNIX sockets with the
18
+// given prefix. If prefix is not given, the prefix will be derived from the
19
+// launched command.
20
+func NewSyslogBackend(prefix string) (b *SyslogBackend, err error) {
21
+ var w *syslog.Writer
22
+ w, err = syslog.New(syslog.LOG_CRIT, prefix)
23
+ return &SyslogBackend{w}, err
24
+}
25
+
26
+// NewSyslogBackendPriority is the same as NewSyslogBackend, but with custom
27
+// syslog priority, like syslog.LOG_LOCAL3|syslog.LOG_DEBUG etc.
28
+func NewSyslogBackendPriority(prefix string, priority syslog.Priority) (b *SyslogBackend, err error) {
29
+ var w *syslog.Writer
30
+ w, err = syslog.New(priority, prefix)
31
+ return &SyslogBackend{w}, err
32
+}
33
+
34
+func (b *SyslogBackend) Log(level Level, calldepth int, rec *Record) error {
35
+ line := rec.Formatted(calldepth + 1)
36
+ switch level {
37
+ case CRITICAL:
38
+ return b.Writer.Crit(line)
39
+ case ERROR:
40
+ return b.Writer.Err(line)
41
+ case WARNING:
42
+ return b.Writer.Warning(line)
43
+ case NOTICE:
44
+ return b.Writer.Notice(line)
45
+ case INFO:
46
+ return b.Writer.Info(line)
47
+ case DEBUG:
48
+ return b.Writer.Debug(line)
49
+ default:
50
+ }
51
+ panic("unhandled log level")
52
+}
daemon/daemon.go
+2
-2
@@ -9,12 +9,12 @@ import (
9
"path"
10
"sync"
11
12
+ logging "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/op/go-logging"
13
core "github.com/jbenet/go-ipfs/core"
14
"github.com/jbenet/go-ipfs/core/commands"
15
u "github.com/jbenet/go-ipfs/util"
15
- logging "github.com/op/go-logging"
16
17
- lock "github.com/camlistore/lock"
17
+ lock "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/camlistore/lock"
18
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
19
)
20