diff --git a/exported_test.go b/exported_test.go index 7db17ee..fa94d57 100644 --- a/exported_test.go +++ b/exported_test.go @@ -74,7 +74,7 @@ func TestPluginOutputIsValid(t *testing.T) { var longServiceOutputReport strings.Builder - fmt.Fprintf( + _, _ = fmt.Fprintf( &longServiceOutputReport, "Datastore Space Summary:%s%s"+ "* Name: %s%s"+ @@ -96,7 +96,7 @@ func TestPluginOutputIsValid(t *testing.T) { nagios.CheckOutputEOL, ) - fmt.Fprintf( + _, _ = fmt.Fprintf( &longServiceOutputReport, "%s---%s%s", nagios.CheckOutputEOL, @@ -104,14 +104,14 @@ func TestPluginOutputIsValid(t *testing.T) { nagios.CheckOutputEOL, ) - fmt.Fprintf( + _, _ = fmt.Fprintf( &longServiceOutputReport, "* vSphere environment: %s%s", "https://vc1.example.com:443/sdk", nagios.CheckOutputEOL, ) - fmt.Fprintf( + _, _ = fmt.Fprintf( &longServiceOutputReport, "* Plugin User Agent: %s%s", "check-vmware/v0.30.6-0-g25fdcdc", @@ -232,7 +232,7 @@ func TestPerformanceDataIsAfterLongServiceOutput(t *testing.T) { var longServiceOutputReport strings.Builder - fmt.Fprintf( + _, _ = fmt.Fprintf( &longServiceOutputReport, "Datastore Space Summary:%s%s"+ "* Name: %s%s"+ @@ -254,7 +254,7 @@ func TestPerformanceDataIsAfterLongServiceOutput(t *testing.T) { nagios.CheckOutputEOL, ) - fmt.Fprintf( + _, _ = fmt.Fprintf( &longServiceOutputReport, "%s---%s%s", nagios.CheckOutputEOL, @@ -262,14 +262,14 @@ func TestPerformanceDataIsAfterLongServiceOutput(t *testing.T) { nagios.CheckOutputEOL, ) - fmt.Fprintf( + _, _ = fmt.Fprintf( &longServiceOutputReport, "* vSphere environment: %s%s", "https://vc1.example.com:443/sdk", nagios.CheckOutputEOL, ) - fmt.Fprintf( + _, _ = fmt.Fprintf( &longServiceOutputReport, "* Plugin User Agent: %s%s", "check-vmware/v0.30.6-0-g25fdcdc", diff --git a/nagios.go b/nagios.go index dce167c..cf56e17 100644 --- a/nagios.go +++ b/nagios.go @@ -315,7 +315,7 @@ func (p *Plugin) ReturnCheckResults() { // If set, call user-provided branding function before emitting // performance data and exiting application. if p.BrandingCallback != nil { - fmt.Fprintf(&output, "%s%s%s", CheckOutputEOL, p.BrandingCallback(), CheckOutputEOL) + _, _ = fmt.Fprintf(&output, "%s%s%s", CheckOutputEOL, p.BrandingCallback(), CheckOutputEOL) } p.handlePerformanceData(&output) @@ -330,7 +330,7 @@ func (p *Plugin) ReturnCheckResults() { // TODO: Perhaps just don't emit anything at all? switch { case p.shouldSkipOSExit: - fmt.Fprintln(os.Stderr, "Skipping os.Exit call as requested.") + _, _ = fmt.Fprintln(os.Stderr, "Skipping os.Exit call as requested.") default: os.Exit(p.ExitStatusCode) } @@ -427,7 +427,20 @@ func (p Plugin) emitOutput(pluginOutput string) { p.outputSink = os.Stdout } - fmt.Fprint(p.outputSink, pluginOutput) + // Attempt to write to output sink. If this fails, send error to + // os.Stderr. If that fails (however unlikely), we have bigger problems + // and should abort. + _, sinkWriteErr := fmt.Fprint(p.outputSink, pluginOutput) + if sinkWriteErr != nil { + _, stdErrWriteErr := fmt.Fprintf( + os.Stderr, + "Failed to write output to given output sink: %s", + sinkWriteErr.Error(), + ) + if stdErrWriteErr != nil { + panic("Failed to initial output sink failure error message to stderr") + } + } } // tryAddDefaultTimeMetric inserts a default `time` performance data metric diff --git a/sections.go b/sections.go index f8b023f..e394e03 100644 --- a/sections.go +++ b/sections.go @@ -33,7 +33,7 @@ func (p Plugin) handleServiceOutputSection(w io.Writer) { // formatting changes to this content, simply emit it as-is. This helps // avoid potential issues with literal characters being interpreted as // formatting verbs. - fmt.Fprint(w, p.ServiceOutput) + _, _ = fmt.Fprint(w, p.ServiceOutput) } // handleErrorsSection is a wrapper around the logic used to handle/process @@ -44,7 +44,7 @@ func (p Plugin) handleErrorsSection(w io.Writer) { // hide the section ... if !p.isErrorsHidden() { - fmt.Fprintf(w, + _, _ = fmt.Fprintf(w, "%s%s**%s**%s%s", CheckOutputEOL, CheckOutputEOL, @@ -54,13 +54,13 @@ func (p Plugin) handleErrorsSection(w io.Writer) { ) if p.LastError != nil { - fmt.Fprintf(w, "* %v%s", p.LastError, CheckOutputEOL) + _, _ = fmt.Fprintf(w, "* %v%s", p.LastError, CheckOutputEOL) } // Process any non-nil errors in the collection. for _, err := range p.Errors { if err != nil { - fmt.Fprintf(w, "* %v%s", err, CheckOutputEOL) + _, _ = fmt.Fprintf(w, "* %v%s", err, CheckOutputEOL) } } @@ -80,7 +80,7 @@ func (p Plugin) handleThresholdsSection(w io.Writer) { // not opted to hide the section ... if !p.isThresholdsSectionHidden() { - fmt.Fprintf(w, + _, _ = fmt.Fprintf(w, "%s**%s**%s%s", CheckOutputEOL, p.getThresholdsLabelText(), @@ -89,7 +89,7 @@ func (p Plugin) handleThresholdsSection(w io.Writer) { ) if p.CriticalThreshold != "" { - fmt.Fprintf(w, + _, _ = fmt.Fprintf(w, "* %s: %v%s", StateCRITICALLabel, p.CriticalThreshold, @@ -98,7 +98,7 @@ func (p Plugin) handleThresholdsSection(w io.Writer) { } if p.WarningThreshold != "" { - fmt.Fprintf(w, + _, _ = fmt.Fprintf(w, "* %s: %v%s", StateWARNINGLabel, p.WarningThreshold, @@ -129,21 +129,21 @@ func (p Plugin) handleLongServiceOutput(w io.Writer) { // ServiceOutput content. switch { case !p.isThresholdsSectionHidden() || !p.isErrorsHidden(): - fmt.Fprintf(w, + _, _ = fmt.Fprintf(w, "%s**%s**%s", CheckOutputEOL, p.getDetailedInfoLabelText(), CheckOutputEOL, ) default: - fmt.Fprint(w, CheckOutputEOL) + _, _ = fmt.Fprint(w, CheckOutputEOL) } // Note: fmt.Println() (and fmt.Fprintln()) has the same issue as `\n`: // Nagios seems to interpret them literally instead of emitting an actual // newline. We work around that by using fmt.Fprintf() for output that is // intended for display within the Nagios web UI. - fmt.Fprintf(w, + _, _ = fmt.Fprintf(w, "%s%v%s", CheckOutputEOL, p.LongServiceOutput, @@ -174,18 +174,18 @@ func (p *Plugin) handlePerformanceData(w io.Writer) { // metrics are provided as a single line, leading with a pipe // character, a space and one or more metrics each separated from // another by a single space. - fmt.Fprint(w, " |") + _, _ = fmt.Fprint(w, " |") // Sort performance data values prior to emitting them so that the // output is consistent across plugin execution. perfData := p.getSortedPerfData() for _, pd := range perfData { - fmt.Fprint(w, pd.String()) + _, _ = fmt.Fprint(w, pd.String()) } // Add final trailing newline to satisfy Nagios plugin output format. - fmt.Fprint(w, CheckOutputEOL) + _, _ = fmt.Fprint(w, CheckOutputEOL) }