You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

107 line
2.3 KiB

  1. // Copyright 2015 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package marbl
  15. import (
  16. "crypto/rand"
  17. "encoding/hex"
  18. "net/http"
  19. "sync"
  20. "github.com/google/martian/log"
  21. "golang.org/x/net/websocket"
  22. )
  23. // Handler exposes marbl logs over websockets.
  24. type Handler struct {
  25. mu sync.RWMutex
  26. subs map[string]chan<- []byte
  27. }
  28. // NewHandler instantiates a Handler with an empty set of subscriptions.
  29. func NewHandler() *Handler {
  30. return &Handler{
  31. subs: make(map[string]chan<- []byte),
  32. }
  33. }
  34. // Write writes frames to all websocket subscribers and returns the number
  35. // of bytes written and an error.
  36. func (h *Handler) Write(b []byte) (int, error) {
  37. h.mu.RLock()
  38. defer h.mu.RUnlock()
  39. for id, framec := range h.subs {
  40. select {
  41. case framec <- b:
  42. default:
  43. log.Errorf("logstream: buffer full for connection, dropping")
  44. close(framec)
  45. delete(h.subs, id)
  46. }
  47. }
  48. return len(b), nil
  49. }
  50. func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
  51. websocket.Server{Handler: h.streamLogs}.ServeHTTP(rw, req)
  52. }
  53. func (h *Handler) streamLogs(conn *websocket.Conn) {
  54. defer conn.Close()
  55. id, err := newID()
  56. if err != nil {
  57. log.Errorf("logstream: failed to create ID: %v", err)
  58. return
  59. }
  60. framec := make(chan []byte, 16384)
  61. h.subscribe(id, framec)
  62. defer h.unsubscribe(id)
  63. for b := range framec {
  64. if err := websocket.Message.Send(conn, b); err != nil {
  65. log.Errorf("logstream: failed to send message: %v", err)
  66. return
  67. }
  68. }
  69. }
  70. func newID() (string, error) {
  71. src := make([]byte, 8)
  72. if _, err := rand.Read(src); err != nil {
  73. return "", err
  74. }
  75. return hex.EncodeToString(src), nil
  76. }
  77. func (h *Handler) unsubscribe(id string) {
  78. h.mu.Lock()
  79. defer h.mu.Unlock()
  80. delete(h.subs, id)
  81. }
  82. func (h *Handler) subscribe(id string, framec chan<- []byte) {
  83. h.mu.Lock()
  84. defer h.mu.Unlock()
  85. h.subs[id] = framec
  86. }