@cryptotaxi247 / kubo / commits / 17f147eff

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 +[![Build Status](https://travis-ci.org/op/go-logging.png)](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 +[![Example Output](examples/example.png)](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