// runStart starts the cockroach node using --stores as the list of // storage devices ("stores") on this machine and --gossip as the list // of "well-known" hosts used to join this node to the cockroach // cluster via the gossip network. func runStart(cmd *cobra.Command, args []string) { info := util.GetBuildInfo() log.Infof("build Vers: %s", info.Vers) log.Infof("build Tag: %s", info.Tag) log.Infof("build Time: %s", info.Time) log.Infof("build Deps: %s", info.Deps) // Default user for servers. Context.User = security.NodeUser // First initialize the Context as it is used in other places. err := Context.Init("start") if err != nil { log.Errorf("failed to initialize context: %s", err) return } log.Info("starting cockroach cluster") stopper := util.NewStopper() stopper.AddWorker() s, err := server.NewServer(Context, stopper) if err != nil { log.Errorf("failed to start Cockroach server: %s", err) return } err = s.Start(false) if err != nil { log.Errorf("cockroach server exited with error: %s", err) return } signalCh := make(chan os.Signal, 1) signal.Notify(signalCh, os.Interrupt, os.Kill) // TODO(spencer): move this behind a build tag. signal.Notify(signalCh, syscall.SIGTERM) // Block until one of the signals above is received or the stopper // is stopped externally (for example, via the quit endpoint). select { case <-stopper.ShouldStop(): stopper.SetStopped() case <-signalCh: log.Infof("initiating graceful shutdown of server") stopper.SetStopped() go func() { s.Stop() }() } select { case <-signalCh: log.Warningf("second signal received, initiating hard shutdown") case <-time.After(time.Minute): log.Warningf("time limit reached, initiating hard shutdown") return case <-stopper.IsStopped(): log.Infof("server drained and shutdown completed") } log.Flush() }
// 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) }
// Logs returns the log entries parsed from the log files stored on // the server. Log entries are returned in reverse chronological order. The // following options are available: // * "starttime" query parameter filters the log entries to only ones that // occurred on or after the "starttime". Defaults to a day ago. // * "endtime" query parameter filters the log entries to only ones that // occurred before on on the "endtime". Defaults to the current time. // * "pattern" query parameter filters the log entries by the provided regexp // pattern if it exists. Defaults to nil. // * "max" query parameter is the hard limit of the number of returned log // entries. Defaults to defaultMaxLogEntries. // * "level" query parameter filters the log entries to be those of the // corresponding severity level or worse. Defaults to "info". func (s *statusServer) Logs(ctx context.Context, req *serverpb.LogsRequest) (*serverpb.JSONResponse, error) { log.Flush() var sev log.Severity if len(req.Level) == 0 { sev = log.InfoLog } else { var sevFound bool sev, sevFound = log.SeverityByName(req.Level) if !sevFound { return nil, fmt.Errorf("level could not be determined: %s", req.Level) } } startTimestamp, err := parseInt64WithDefault( req.StartTime, timeutil.Now().AddDate(0, 0, -1).UnixNano()) if err != nil { return nil, grpc.Errorf(codes.InvalidArgument, "StartTime could not be parsed: %s", err) } endTimestamp, err := parseInt64WithDefault(req.EndTime, timeutil.Now().UnixNano()) if err != nil { return nil, grpc.Errorf(codes.InvalidArgument, "EndTime could not be parsed: %s", err) } if startTimestamp > endTimestamp { return nil, grpc.Errorf(codes.InvalidArgument, "StartTime: %d should not be greater than endtime: %d", startTimestamp, endTimestamp) } maxEntries, err := parseInt64WithDefault(req.Max, defaultMaxLogEntries) if err != nil { return nil, grpc.Errorf(codes.InvalidArgument, "Max could not be parsed: %s", err) } if maxEntries < 1 { return nil, grpc.Errorf(codes.InvalidArgument, "Max: %d should be set to a value greater than 0", maxEntries) } var regex *regexp.Regexp if len(req.Pattern) > 0 { if regex, err = regexp.Compile(req.Pattern); err != nil { return nil, grpc.Errorf(codes.InvalidArgument, "regex pattern could not be compiled: %s", err) } } entries, err := log.FetchEntriesFromFiles(sev, startTimestamp, endTimestamp, int(maxEntries), regex) if err != nil { return nil, err } return marshalJSONResponse(entries) }
// handleLocalLogFiles handles GET requests for list of available logs. func (s *statusServer) handleLocalLogFiles(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { log.Flush() logFiles, err := log.ListLogFiles() if err != nil { log.Error(err) w.WriteHeader(http.StatusInternalServerError) return } b, contentType, err := util.MarshalResponse(r, logFiles, []util.EncodingType{util.JSONEncoding}) if err != nil { log.Error(err) w.WriteHeader(http.StatusInternalServerError) return } w.Header().Set(util.ContentTypeHeader, contentType) w.Write(b) }
// LogFilesList returns a list of available log files. func (s *statusServer) LogFilesList(ctx context.Context, req *serverpb.LogFilesListRequest) (*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.LogFilesList(ctx, req) } log.Flush() logFiles, err := log.ListLogFiles() if err != nil { return nil, err } return marshalJSONResponse(logFiles) }
// runStart starts the cockroach node using --stores as the list of // storage devices ("stores") on this machine and --gossip as the list // of "well-known" hosts used to join this node to the cockroach // cluster via the gossip network. func runStart(cmd *cobra.Command, args []string) { info := util.GetBuildInfo() log.Infof("build Vers: %s", info.Vers) log.Infof("build Tag: %s", info.Tag) log.Infof("build Time: %s", info.Time) log.Infof("build Deps: %s", info.Deps) // Default user for servers. context.User = security.NodeUser if context.EphemeralSingleNode { context.Stores = "mem=1073741824" context.GossipBootstrap = server.SelfGossipAddr runInit(cmd, args) } else { if err := context.InitStores(); err != nil { log.Errorf("failed to initialize stores: %s", err) return } } if err := context.InitNode(); err != nil { log.Errorf("failed to initialize node: %s", err) return } log.Info("starting cockroach cluster") stopper := stop.NewStopper() s, err := server.NewServer(context, stopper) if err != nil { log.Errorf("failed to start Cockroach server: %s", err) return } if err := s.Start(false); err != nil { log.Errorf("cockroach server exited with error: %s", err) return } if context.EphemeralSingleNode { // TODO(tamird): pass this to BootstrapRange rather than doing it // at runtime. This was quicker, though. db, clientStopper := makeDBClient() if err := configutil.SetDefaultRangeReplicaNum(db, 1); err != nil { log.Errorf("failed to set default replica number: %s", err) } clientStopper.Stop() } signalCh := make(chan os.Signal, 1) signal.Notify(signalCh, os.Interrupt, os.Kill) // TODO(spencer): move this behind a build tag. signal.Notify(signalCh, syscall.SIGTERM) // Block until one of the signals above is received or the stopper // is stopped externally (for example, via the quit endpoint). select { case <-stopper.ShouldStop(): case <-signalCh: go s.Stop() } log.Info("initiating graceful shutdown of server") go func() { ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() for { select { case <-ticker.C: if log.V(1) { log.Infof("running tasks:\n%s", stopper.RunningTasks()) } log.Infof("%d running tasks", stopper.NumTasks()) case <-stopper.ShouldStop(): return } } }() select { case <-signalCh: log.Warningf("second signal received, initiating hard shutdown") case <-time.After(time.Minute): log.Warningf("time limit reached, initiating hard shutdown") case <-stopper.IsStopped(): log.Infof("server drained and shutdown completed") } log.Flush() }
// handleLocalLog returns the log entries parsed from the log files stored on // the server. Log entries are returned in reverse chronological order. The // following options are available: // * "starttime" query parameter filters the log entries to only ones that // occurred on or after the "starttime". Defaults to a day ago. // * "endtime" query parameter filters the log entries to only ones that // occurred before on on the "endtime". Defaults to the current time. // * "pattern" query parameter filters the log entries by the provided regexp // pattern if it exists. Defaults to nil. // * "max" query parameter is the hard limit of the number of returned log // entries. Defaults to defaultMaxLogEntries. // * "level" which is an optional part of the URL filters the log entries to be // those of the corresponding severity level or worse. Defaults to "info". func (s *statusServer) handleLocalLog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { log.Flush() level := ps.ByName("level") var sev log.Severity if len(level) == 0 { sev = log.InfoLog } else { var sevFound bool sev, sevFound = log.SeverityByName(level) if !sevFound { w.WriteHeader(http.StatusBadRequest) fmt.Fprintf(w, "could not determine level %s", level) return } } startTimestamp, err := parseInt64WithDefault( r.URL.Query().Get("starttime"), time.Now().AddDate(0, 0, -1).UnixNano()) if err != nil { w.WriteHeader(http.StatusBadRequest) fmt.Fprintf(w, "starttime could not be parsed:%s", err) return } endTimestamp, err := parseInt64WithDefault( r.URL.Query().Get("endtime"), time.Now().UnixNano()) if err != nil { w.WriteHeader(http.StatusBadRequest) fmt.Fprintf(w, "endtime could not be parsed:%s", err) return } if startTimestamp > endTimestamp { w.WriteHeader(http.StatusBadRequest) fmt.Fprintf(w, "startime:%d is greater than endtime:%d", startTimestamp, endTimestamp) return } maxEntries, err := parseInt64WithDefault( r.URL.Query().Get("max"), defaultMaxLogEntries) if err != nil { w.WriteHeader(http.StatusBadRequest) fmt.Fprintf(w, "max could not be parsed:%s", err) return } if maxEntries < 1 { w.WriteHeader(http.StatusBadRequest) fmt.Fprint(w, "max must be set to a value greater than 0") return } pattern := r.URL.Query().Get("pattern") var regex *regexp.Regexp if len(pattern) > 0 { if regex, err = regexp.Compile(pattern); err != nil { w.WriteHeader(http.StatusBadRequest) fmt.Fprintf(w, "could not compile regex pattern:%s", err) return } } entries, err := log.FetchEntriesFromFiles(sev, startTimestamp, endTimestamp, int(maxEntries), regex) if err != nil { log.Error(err) w.WriteHeader(http.StatusInternalServerError) return } 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) }