Merge lp:~rogpeppe/juju-core/313-jsoncodec-optional-log into lp:~juju/juju-core/trunk

Proposed by Roger Peppe
Status: Work in progress
Proposed branch: lp:~rogpeppe/juju-core/313-jsoncodec-optional-log
Merge into: lp:~juju/juju-core/trunk
Prerequisite: lp:~rogpeppe/juju-core/312-api-jobs
Diff against target: 326 lines (+145/-30) (has conflicts)
4 files modified
rpc/jsoncodec/codec.go (+31/-17)
rpc/jsoncodec/codec_test.go (+104/-10)
rpc/jsoncodec/conn.go (+2/-3)
state/apiserver/apiserver.go (+8/-0)
Text conflict in cmd/jujud/agent_test.go
Text conflict in cmd/jujud/bootstrap_test.go
Text conflict in environs/agent/agent.go
Contents conflict in state/api/machine.go
Text conflict in state/api/params/params.go
Text conflict in state/apiserver/apiserver.go
Contents conflict in state/apiserver/machine.go
Contents conflict in state/apiserver/machine_test.go
Text conflict in state/apiserver/utils.go
To merge this branch: bzr merge lp:~rogpeppe/juju-core/313-jsoncodec-optional-log
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+165736@code.launchpad.net

Description of the change

rpc/jsoncodec: optional logging

Because we're now using the same codec on
both client and server, we were seeing each message
logged twice when testing. This changes
things so we only log on the server side.

https://codereview.appspot.com/9692044/

To post a comment you must log in.
Revision history for this message
Roger Peppe (rogpeppe) wrote :

Reviewers: mp+165736_code.launchpad.net,

Message:
Please take a look.

Description:
rpc/jsoncodec: optional logging

Because we're now using the same codec on
both client and server, we were seeing each message
logged twice when testing. This changes
things so we only log on the server side.

https://code.launchpad.net/~rogpeppe/juju-core/313-jsoncodec-optional-log/+merge/165736

Requires:
https://code.launchpad.net/~rogpeppe/juju-core/312-api-jobs/+merge/165705

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/9692044/

Affected files:
   A [revision details]
   M rpc/jsoncodec/codec.go
   M rpc/jsoncodec/codec_test.go
   M rpc/jsoncodec/conn.go
   M state/apiserver/apiserver.go

Revision history for this message
Roger Peppe (rogpeppe) wrote :
Revision history for this message
William Reade (fwereade) wrote :

NOT LGTM I'm afraid.

https://codereview.appspot.com/9692044/diff/5002/rpc/jsoncodec/codec.go
File rpc/jsoncodec/codec.go (right):

https://codereview.appspot.com/9692044/diff/5002/rpc/jsoncodec/codec.go#newcode44
rpc/jsoncodec/codec.go:44: // called before the codec is used for
serving RPC requests.
This is a timebomb that will explode as soon as we have dynamic logging
levels, and someone notices that the API server doesn't respect them. If
you're going to implement this, please do it properly...

https://codereview.appspot.com/9692044/

Revision history for this message
Roger Peppe (rogpeppe) wrote :

Please take a look.

https://codereview.appspot.com/9692044/diff/5002/rpc/jsoncodec/codec.go
File rpc/jsoncodec/codec.go (right):

https://codereview.appspot.com/9692044/diff/5002/rpc/jsoncodec/codec.go#newcode44
rpc/jsoncodec/codec.go:44: // called before the codec is used for
serving RPC requests.
On 2013/05/27 20:29:44, fwereade wrote:
> This is a timebomb that will explode as soon as we have dynamic
logging levels,
> and someone notices that the API server doesn't respect them. If
you're going to
> implement this, please do it properly...

Done.

https://codereview.appspot.com/9692044/

Revision history for this message
William Reade (fwereade) wrote :
Revision history for this message
Ian Booth (wallyworld) wrote :
Revision history for this message
Roger Peppe (rogpeppe) wrote :

On 2013/06/21 01:28:02, wallyworld wrote:
> LGTM

merged as https://codereview.appspot.com/10410046/

https://codereview.appspot.com/9692044/

Unmerged revisions

1243. By Roger Peppe

rpc/jsoncodec: s/LogMessages/SetLogging/

1242. By Roger Peppe

Merged 312-api-jobs into 313-jsoncodec-optional-log.

1241. By Roger Peppe

Merged 312-api-jobs into 313-jsoncodec-optional-log.

1240. By Roger Peppe

rpc/jsoncodec: remove unnecessary logic in test code

1239. By Roger Peppe

rpc/jsoncodec: make log messaging configurable

1238. By Roger Peppe

api: implement Machine.Jobs

1237. By Roger Peppe

merge trunk

1236. By Roger Peppe

cmd/juju: revert bogus change

1235. By Roger Peppe

cmd/jujud: change password for machine agent

1234. By Roger Peppe

gofmt

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'rpc/jsoncodec/codec.go'
2--- rpc/jsoncodec/codec.go 2013-05-28 07:01:54 +0000
3+++ rpc/jsoncodec/codec.go 2013-06-07 17:45:32 +0000
4@@ -8,6 +8,7 @@
5 "launchpad.net/juju-core/log"
6 "launchpad.net/juju-core/rpc"
7 "sync"
8+ "sync/atomic"
9 )
10
11 // JSONConn sends and receives messages to an underlying connection
12@@ -20,26 +21,39 @@
13 Close() error
14 }
15
16-var logRequests = true
17-
18-// codec implements rpc.Codec for a connection.
19-type codec struct {
20+// Codec implements rpc.Codec for a connection.
21+type Codec struct {
22 // msg holds the message that's just been read by ReadHeader, so
23 // that the body can be read by ReadBody.
24- msg inMsg
25- conn JSONConn
26- mu sync.Mutex
27- closing bool
28+ msg inMsg
29+ conn JSONConn
30+ logMessages int32
31+ mu sync.Mutex
32+ closing bool
33 }
34
35 // New returns an rpc codec that uses conn to send and receive
36 // messages.
37-func New(conn JSONConn) rpc.Codec {
38- return &codec{
39+func New(conn JSONConn) *Codec {
40+ return &Codec{
41 conn: conn,
42 }
43 }
44
45+// SetLogging sets whether messages will be logged
46+// by the codec.
47+func (c *Codec) SetLogging(on bool) {
48+ val := int32(0)
49+ if on {
50+ val = 1
51+ }
52+ atomic.StoreInt32(&c.logMessages, val)
53+}
54+
55+func (c *Codec) isLogging() bool {
56+ return atomic.LoadInt32(&c.logMessages) != 0
57+}
58+
59 // inMsg holds an incoming message. We don't know the type of the
60 // parameters or response yet, so we delay parsing by storing them
61 // in a RawMessage.
62@@ -66,23 +80,23 @@
63 Response interface{} `json:",omitempty"`
64 }
65
66-func (c *codec) Close() error {
67+func (c *Codec) Close() error {
68 c.mu.Lock()
69 c.closing = true
70 c.mu.Unlock()
71 return c.conn.Close()
72 }
73
74-func (c *codec) isClosing() bool {
75+func (c *Codec) isClosing() bool {
76 c.mu.Lock()
77 defer c.mu.Unlock()
78 return c.closing
79 }
80
81-func (c *codec) ReadHeader(hdr *rpc.Header) error {
82+func (c *Codec) ReadHeader(hdr *rpc.Header) error {
83 c.msg = inMsg{} // avoid any potential cross-message contamination.
84 var err error
85- if logRequests {
86+ if c.isLogging() {
87 var m json.RawMessage
88 err = c.conn.Receive(&m)
89 if err == nil {
90@@ -111,7 +125,7 @@
91 return nil
92 }
93
94-func (c *codec) ReadBody(body interface{}, isRequest bool) error {
95+func (c *Codec) ReadBody(body interface{}, isRequest bool) error {
96 if body == nil {
97 return nil
98 }
99@@ -129,7 +143,7 @@
100 return json.Unmarshal(rawBody, body)
101 }
102
103-func (c *codec) WriteMessage(hdr *rpc.Header, body interface{}) error {
104+func (c *Codec) WriteMessage(hdr *rpc.Header, body interface{}) error {
105 r := &outMsg{
106 RequestId: hdr.RequestId,
107
108@@ -145,7 +159,7 @@
109 } else {
110 r.Response = body
111 }
112- if logRequests {
113+ if c.isLogging() {
114 data, err := json.Marshal(r)
115 if err != nil {
116 log.Debugf("rpc/jsoncodec: -> marshal error: %v", err)
117
118=== modified file 'rpc/jsoncodec/codec_test.go'
119--- rpc/jsoncodec/codec_test.go 2013-05-15 12:34:10 +0000
120+++ rpc/jsoncodec/codec_test.go 2013-06-07 17:45:32 +0000
121@@ -7,15 +7,19 @@
122 . "launchpad.net/gocheck"
123 "launchpad.net/juju-core/rpc"
124 "launchpad.net/juju-core/rpc/jsoncodec"
125+ "launchpad.net/juju-core/testing"
126 "reflect"
127- "testing"
128+ "regexp"
129+ stdtesting "testing"
130 )
131
132-type suite struct{}
133-
134-var _ = Suite(suite{})
135-
136-func TestPackage(t *testing.T) {
137+type suite struct {
138+ testing.LoggingSuite
139+}
140+
141+var _ = Suite(&suite{})
142+
143+func TestPackage(t *stdtesting.T) {
144 TestingT(t)
145 }
146
147@@ -52,7 +56,7 @@
148 expectBody: &value{X: "result"},
149 }}
150
151-func (suite) TestRead(c *C) {
152+func (*suite) TestRead(c *C) {
153 for i, test := range readTests {
154 c.Logf("test %d", i)
155 codec := jsoncodec.New(&testConn{
156@@ -75,7 +79,97 @@
157 }
158 }
159
160-func (suite) TestErrorAfterClose(c *C) {
161+func (*suite) TestReadHeaderLogsRequests(c *C) {
162+ msg := `{"RequestId":1,"Type": "foo","Id": "id","Request":"frob","Params":{"X":"param"}}`
163+ codec := jsoncodec.New(&testConn{
164+ readMsgs: []string{msg, msg, msg},
165+ })
166+ // Check that logging is off by default
167+ var h rpc.Header
168+ err := codec.ReadHeader(&h)
169+ c.Assert(err, IsNil)
170+ c.Assert(c.GetTestLog(), Matches, "")
171+
172+ // Check that we see a log message when we switch logging on.
173+ codec.SetLogging(true)
174+ err = codec.ReadHeader(&h)
175+ c.Assert(err, IsNil)
176+ c.Assert(c.GetTestLog(), Matches, ".*DEBUG rpc/jsoncodec: <- "+regexp.QuoteMeta(msg)+`\n`)
177+
178+ // Check that we can switch it off again
179+ codec.SetLogging(false)
180+ err = codec.ReadHeader(&h)
181+ c.Assert(err, IsNil)
182+ c.Assert(c.GetTestLog(), Matches, ".*DEBUG rpc/jsoncodec: <- "+regexp.QuoteMeta(msg)+`\n`)
183+}
184+
185+func (*suite) TestWriteMessageLogsRequests(c *C) {
186+ codec := jsoncodec.New(&testConn{})
187+ h := rpc.Header{
188+ RequestId: 1,
189+ Type: "foo",
190+ Id: "id",
191+ Request: "frob",
192+ }
193+
194+ // Check that logging is off by default
195+ err := codec.WriteMessage(&h, value{X: "param"})
196+ c.Assert(err, IsNil)
197+ c.Assert(c.GetTestLog(), Matches, "")
198+
199+ // Check that we see a log message when we switch logging on.
200+ codec.SetLogging(true)
201+ err = codec.WriteMessage(&h, value{X: "param"})
202+ c.Assert(err, IsNil)
203+ msg := `{"RequestId":1,"Type":"foo","Id":"id","Request":"frob","Params":{"X":"param"}}`
204+ c.Assert(c.GetTestLog(), Matches, `.*DEBUG rpc/jsoncodec: -> `+regexp.QuoteMeta(msg)+`\n`)
205+
206+ // Check that we can switch it off again
207+ codec.SetLogging(false)
208+ err = codec.WriteMessage(&h, value{X: "param"})
209+ c.Assert(err, IsNil)
210+ c.Assert(c.GetTestLog(), Matches, `.*DEBUG rpc/jsoncodec: -> `+regexp.QuoteMeta(msg)+`\n`)
211+}
212+
213+func (*suite) TestConcurrentSetLoggingAndWrite(c *C) {
214+ // If log messages are not set atomically, this
215+ // test will fail when run under the race detector.
216+ codec := jsoncodec.New(&testConn{})
217+ done := make(chan struct{})
218+ go func() {
219+ codec.SetLogging(true)
220+ done <- struct{}{}
221+ }()
222+ h := rpc.Header{
223+ RequestId: 1,
224+ Type: "foo",
225+ Id: "id",
226+ Request: "frob",
227+ }
228+ err := codec.WriteMessage(&h, value{X: "param"})
229+ c.Assert(err, IsNil)
230+ <-done
231+}
232+
233+func (*suite) TestConcurrentSetLoggingAndRead(c *C) {
234+ // If log messages are not set atomically, this
235+ // test will fail when run under the race detector.
236+ msg := `{"RequestId":1,"Type": "foo","Id": "id","Request":"frob","Params":{"X":"param"}}`
237+ codec := jsoncodec.New(&testConn{
238+ readMsgs: []string{msg, msg, msg},
239+ })
240+ done := make(chan struct{})
241+ go func() {
242+ codec.SetLogging(true)
243+ done <- struct{}{}
244+ }()
245+ var h rpc.Header
246+ err := codec.ReadHeader(&h)
247+ c.Assert(err, IsNil)
248+ <-done
249+}
250+
251+func (*suite) TestErrorAfterClose(c *C) {
252 conn := &testConn{
253 err: errors.New("some error"),
254 }
255@@ -105,7 +199,7 @@
256 Request: "frob",
257 },
258 body: &value{X: "param"},
259- expect: `{"RequestId": 1, "Type": "foo", "Id": "id", "Request": "frob", "Params": {"X": "param"}}`,
260+ expect: `{"RequestId": 1, "Type": "foo","Id":"id", "Request": "frob", "Params": {"X": "param"}}`,
261 }, {
262 hdr: &rpc.Header{
263 RequestId: 2,
264@@ -121,7 +215,7 @@
265 expect: `{"RequestId": 3, "Response": {"X": "result"}}`,
266 }}
267
268-func (suite) TestWrite(c *C) {
269+func (*suite) TestWrite(c *C) {
270 for i, test := range writeTests {
271 c.Logf("test %d", i)
272 var conn testConn
273
274=== modified file 'rpc/jsoncodec/conn.go'
275--- rpc/jsoncodec/conn.go 2013-05-16 17:31:36 +0000
276+++ rpc/jsoncodec/conn.go 2013-06-07 17:45:32 +0000
277@@ -3,13 +3,12 @@
278 import (
279 "code.google.com/p/go.net/websocket"
280 "encoding/json"
281- "launchpad.net/juju-core/rpc"
282 "net"
283 )
284
285 // NewWebsocket returns an rpc codec that uses the given websocket
286 // connection to send and receive messages.
287-func NewWebsocket(conn *websocket.Conn) rpc.Codec {
288+func NewWebsocket(conn *websocket.Conn) *Codec {
289 return New(wsJSONConn{conn})
290 }
291
292@@ -31,7 +30,7 @@
293
294 // NewNet returns an rpc codec that uses the given net
295 // connection to send and receive messages.
296-func NewNet(conn net.Conn) rpc.Codec {
297+func NewNet(conn net.Conn) *Codec {
298 return New(&netConn{
299 enc: json.NewEncoder(conn),
300 dec: json.NewDecoder(conn),
301
302=== modified file 'state/apiserver/apiserver.go'
303--- state/apiserver/apiserver.go 2013-06-06 17:09:49 +0000
304+++ state/apiserver/apiserver.go 2013-06-07 17:45:32 +0000
305@@ -96,6 +96,7 @@
306 }
307
308 func (srv *Server) serveConn(wsConn *websocket.Conn) error {
309+<<<<<<< TREE
310 conn := rpc.NewConn(jsoncodec.NewWebsocket(wsConn))
311 serverError := func(err error) error {
312 if err := common.ServerError(err); err != nil {
313@@ -103,6 +104,13 @@
314 }
315 return nil
316 }
317+=======
318+ codec := jsoncodec.NewWebsocket(wsConn)
319+ if log.Debug {
320+ codec.SetLogging(true)
321+ }
322+ conn := rpc.NewConn(codec)
323+>>>>>>> MERGE-SOURCE
324 if err := conn.Serve(newStateServer(srv), serverError); err != nil {
325 return err
326 }

Subscribers

People subscribed via source and target branches