// LogFile returns a single log file. func (s *statusServer) LogFile(ctx context.Context, req *serverpb.LogFileRequest) (*serverpb.JSONResponse, error) { nodeID, local, err := s.parseNodeID(req.NodeId) if err != nil { return nil, grpc.Errorf(codes.InvalidArgument, err.Error()) } if !local { status, err := s.dialNode(nodeID) if err != nil { return nil, err } return status.LogFile(ctx, req) } log.Flush() reader, err := log.GetLogReader(req.File, true /* restricted */) if reader == nil || err != nil { return nil, fmt.Errorf("log file %s could not be opened: %s", req.File, err) } defer reader.Close() entry := log.Entry{} var entries []log.Entry decoder := log.NewEntryDecoder(reader) for { if err := decoder.Decode(&entry); err != nil { if err == io.EOF { break } return nil, err } entries = append(entries, entry) } return marshalJSONResponse(entries) }
// handleLocalLogFile handles GET requests for a single log. If no filename is // available, it returns 404. The log contents are returned in structured // format as JSON. func (s *statusServer) handleLocalLogFile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { log.Flush() file := ps.ByName("file") reader, err := log.GetLogReader(file, false /* !allowAbsolute */) if reader == nil || err != nil { log.Errorf("unable to open log file %s: %s", file, err) http.NotFound(w, r) return } defer reader.Close() entry := log.LogEntry{} var entries []log.LogEntry decoder := log.NewEntryDecoder(reader) for { if err := decoder.Decode(&entry); err != nil { if err == io.EOF { break } log.Error(err) w.WriteHeader(http.StatusInternalServerError) return } entries = append(entries, entry) } b, contentType, err := util.MarshalResponse(r, entries, []util.EncodingType{util.JSONEncoding}) if err != nil { log.Error(err) w.WriteHeader(http.StatusInternalServerError) return } w.Header().Set(util.ContentTypeHeader, contentType) w.Write(b) }