func (s *HTTPServer) AgentMonitor(resp http.ResponseWriter, req *http.Request) (interface{}, error) { // Only GET supported if req.Method != "GET" { resp.WriteHeader(405) return nil, nil } var args structs.DCSpecificRequest args.Datacenter = s.agent.config.Datacenter s.parseToken(req, &args.Token) // Validate that the given token has operator permissions var reply structs.RaftConfigurationResponse if err := s.agent.RPC("Operator.RaftGetConfiguration", &args, &reply); err != nil { return nil, err } // Get the provided loglevel logLevel := req.URL.Query().Get("loglevel") if logLevel == "" { logLevel = "INFO" } // Upper case the log level logLevel = strings.ToUpper(logLevel) // Create a level filter filter := logger.LevelFilter() filter.MinLevel = logutils.LogLevel(logLevel) if !logger.ValidateLevelFilter(filter.MinLevel, filter) { resp.WriteHeader(400) resp.Write([]byte(fmt.Sprintf("Unknown log level: %s", filter.MinLevel))) return nil, nil } flusher, ok := resp.(http.Flusher) if !ok { return nil, fmt.Errorf("Streaming not supported") } // Set up a log handler handler := &httpLogHandler{ filter: filter, logCh: make(chan string, 512), logger: s.logger, } s.agent.logWriter.RegisterHandler(handler) defer s.agent.logWriter.DeregisterHandler(handler) notify := resp.(http.CloseNotifier).CloseNotify() // Stream logs until the connection is closed for { select { case <-notify: s.agent.logWriter.DeregisterHandler(handler) if handler.droppedCount > 0 { s.agent.logger.Printf("[WARN] agent: Dropped %d logs during monitor request", handler.droppedCount) } return nil, nil case log := <-handler.logCh: resp.Write([]byte(log + "\n")) flusher.Flush() } } return nil, nil }