ADMIN API to turn Go CPU profiling on/off
()
| 554 | |
| 555 | // ADMIN API to turn Go CPU profiling on/off |
| 556 | func (h *handler) handleProfiling() (err error) { |
| 557 | profileName := h.PathVar("profilename") |
| 558 | isCPUProfile := profileName == "" |
| 559 | |
| 560 | var params struct { |
| 561 | File string `json:"file"` |
| 562 | } |
| 563 | body, err := h.readBody() |
| 564 | if err != nil { |
| 565 | return err |
| 566 | } |
| 567 | if len(body) > 0 { |
| 568 | if err = base.JSONUnmarshal(body, ¶ms); err != nil { |
| 569 | return err |
| 570 | } |
| 571 | } |
| 572 | |
| 573 | // Handle no file |
| 574 | if params.File == "" { |
| 575 | if isCPUProfile { |
| 576 | base.InfofCtx(h.ctx(), base.KeyAll, "... ending CPU profile") |
| 577 | pprof.StopCPUProfile() |
| 578 | filename := h.server.CloseCpuPprofFile(h.ctx()) |
| 579 | base.Audit(h.ctx(), base.AuditIDSyncGatewayProfiling, base.AuditFields{base.AuditFieldPprofProfileType: "cpu", base.AuditFieldFileName: filename}) |
| 580 | return nil |
| 581 | } |
| 582 | return base.HTTPErrorf(http.StatusBadRequest, "Missing JSON 'file' parameter") |
| 583 | } |
| 584 | |
| 585 | f, err := os.Create(params.File) |
| 586 | if err != nil { |
| 587 | return err |
| 588 | } |
| 589 | |
| 590 | if isCPUProfile { |
| 591 | base.InfofCtx(h.ctx(), base.KeyAll, "Starting CPU profile to %s ...", base.UD(params.File)) |
| 592 | base.Audit(h.ctx(), base.AuditIDSyncGatewayProfiling, base.AuditFields{base.AuditFieldPprofProfileType: "cpu (start)", base.AuditFieldFileName: params.File}) |
| 593 | if err = pprof.StartCPUProfile(f); err != nil { |
| 594 | if fileError := os.Remove(params.File); fileError != nil { |
| 595 | base.InfofCtx(h.ctx(), base.KeyAll, "Error removing file: %s", base.UD(params.File)) |
| 596 | } |
| 597 | return err |
| 598 | } |
| 599 | h.server.SetCpuPprofFile(f) |
| 600 | return err |
| 601 | } else if profile := pprof.Lookup(profileName); profile != nil { |
| 602 | base.InfofCtx(h.ctx(), base.KeyAll, "Writing %q profile to %s ...", profileName, base.UD(params.File)) |
| 603 | err = profile.WriteTo(f, 0) |
| 604 | base.Audit(h.ctx(), base.AuditIDSyncGatewayProfiling, base.AuditFields{base.AuditFieldPprofProfileType: profileName, base.AuditFieldFileName: params.File}) |
| 605 | } else { |
| 606 | err = base.HTTPErrorf(http.StatusNotFound, "No such profile %q", profileName) |
| 607 | } |
| 608 | |
| 609 | if fileCloseError := f.Close(); fileCloseError != nil { |
| 610 | base.WarnfCtx(h.ctx(), "Error closing profile file: %v", fileCloseError) |
| 611 | } |
| 612 | |
| 613 | return err |
nothing calls this directly
no test coverage detected