Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add input plugin for monit #6850

Merged
merged 10 commits into from
Jan 22, 2020
Merged

Add input plugin for monit #6850

merged 10 commits into from
Jan 22, 2020

Conversation

SirishaGopigiri
Copy link
Contributor

@SirishaGopigiri SirishaGopigiri commented Jan 3, 2020

closes #230

Required for all PRs:

  • Signed CLA.
  • Associated README.md updated.
  • Has appropriate unit tests.

Address string
BasicAuthUsername string
BasicAuthPassword string
parser parsers.Parser
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove parser, unused.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please check.

Comment on lines 187 to 188
basic_auth_username = ""
basic_auth_password = ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call these basic_username and basic_password, or just username and password. This is to keep in line with existing plugins.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please check.

Comment on lines 205 to 207
func (m *Monit) SetParser(parser parsers.Parser) {
m.parser = parser
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove, unused.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please check.

Comment on lines 169 to 171
Address string
BasicAuthUsername string
BasicAuthPassword string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On all the exported fields, add a struct tag for the toml:

Address           string `toml:"address"`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please check.

decoder := xml.NewDecoder(resp.Body)
decoder.CharsetReader = charset.NewReaderLabel
if err := decoder.Decode(&status); err != nil {
return fmt.Errorf("Cannot parse input with error: %v\n", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjust error string to match Go style guideline, the format string should be something like:

"error parsing input: %v"

https://github.com/golang/go/wiki/CodeReviewComments#error-strings

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please check.

} else if service.Type == "7" {
fields["last_started_time"] = service.Program.Started * 1000
fields["program_status"] = service.Program.Status
fields["output"] = service.Program.Output
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the program output? If so we should probably skip this item due to potential length. If we would like to keep it then we need to convert/verify that the output is UTF-8 encoded and that the output isn't too large.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please check

fields["mem_kb_total"] = service.Memory.KilobyteTotal
fields["mem_percent"] = service.Memory.Percent
fields["mem_percent_total"] = service.Memory.PercentTotal
fields["service_uptime"] = service.Uptime
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make time units consistent with other time fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please check

func monitoringMode(s Service) string {
switch s.MonitorMode {
case 0:
return "Monitoring in Active mode"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest we make these strings consistent with the Monit web interface, in mine:

Monitoring status:  Monitored
Monitoring mode:    active

We should try to be consistent like this in any string conversions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please check

fields["status"] = serviceStatus(service)
fields["monitoring_status_code"] = service.MonitoringStatus
fields["monitoring_status"] = monitoringStatus(service)
fields["monitoring_mode_status"] = monitoringMode(service)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

monitoring_mode to match web interface

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please check

fields["status_code"] = service.Status
fields["status"] = serviceStatus(service)
fields["monitoring_status_code"] = service.MonitoringStatus
fields["monitoring_status"] = monitoringStatus(service)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make status, monitoring status and monitoring mode as tags.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Please check

@danielnelson danielnelson changed the title Feature/monitplugin Add input plugin for monit Jan 6, 2020
@danielnelson danielnelson mentioned this pull request Jan 7, 2020
3 tasks
@SirishaGopigiri SirishaGopigiri changed the title Add input plugin for monit [WIP] Add input plugin for monit Jan 7, 2020
Sirisha Gopigiri and others added 4 commits January 10, 2020 12:39
Aligning code to telegraf standards and added some more testcases

Co-authored-by: sirishagopigiri <[email protected]>
Co-authored-by: susancoombs <[email protected]>
Aligning code to telegraf standards and added some more testcases

Co-authored-by: sirishagopigiri <[email protected]>
Co-authored-by: susancoombs <[email protected]>
Co-authored-by: SirishaGopigiri <[email protected]>
Co-authored-by: susancoombs <[email protected]>
@sjwang90 sjwang90 added this to the 1.14.0 milestone Jan 13, 2020
Copy link
Contributor

@danielnelson danielnelson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are a few more ideas, mostly around naming, that I think we should do.

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When setting up the Monit HTTPD server, you can use the ALLOW option to limit who can connect to the server. Let's add a test if possible and make sure we provide a good error message should the plugin hit this case.

https://mmonit.com/monit/documentation/monit.html#TCP-PORT

} else if s.Link.Duplex == 0 {
return "Simplex Mode"
} else {
return "Unknown Mode"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have the strings be: "duplex", "simplex", "unknown"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

case 1:
return "Monitoring mode: passive"
}
return "Monitoring mode: unknown"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have the strings be "active", "passive", "unknown". This is consistent with the terminology of Monit without being too repetitive with the tag key.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

case 4:
return "Monitoring status: Waiting"
}
return "Monitoring status: Not monitored"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"monitored", "initializing", "waiting", "not_monitored"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

func serviceStatus(s Service) string {
var status string

if s.MonitoringStatus == 0 || s.MonitoringStatus == 2 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid combining the meaning of multiple fields, we should just directly report from the status. So this function could return "running" or "failure".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

plugins/inputs/monit/monit.go Show resolved Hide resolved
Comment on lines 250 to 253
tags := map[string]string{"address": m.Address,
"version": status.Server.Version,
"hostname": status.Server.LocalHostname,
"platform_name": status.Platform.Name}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the address tag, and rename the hostname tag to "source". This will be consistent with #4413.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

fields["swap_percent"] = service.System.Swap.Percent
acc.AddFields("monit_system", fields, tags)
} else if service.Type == fifo {
fields["permissions"] = service.Mode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call this mode

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

fields["permissions"] = service.Mode
acc.AddFields("monit_fifo", fields, tags)
} else if service.Type == program {
fields["last_started_time"] = service.Program.Started * 10000000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call this field program_started

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

acc.AddFields("monit_directory", fields, tags)
} else if service.Type == file {
fields["size"] = service.Size
fields["permissions"] = service.Mode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call this field mode

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Co-authored-by: SirishaGopigiri <[email protected]>
Co-authored-by: susancoombs <[email protected]>
@SirishaGopigiri SirishaGopigiri changed the title [WIP] Add input plugin for monit Add input plugin for monit Jan 22, 2020
@danielnelson danielnelson merged commit 9fd400c into influxdata:master Jan 22, 2020
- monitoring_status
- monitoring_mode

### Measurements & Fields:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L31-33 looks like leftover boilerplate that needs to be deleted. Measurements and Fields are covered below

- monitoring_mode_code

### Measurement & Fields:
Fields for Monit service type Filesystem:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filesystem shouldn't be capitalized if other service types aren't

Timeout internal.Duration `toml:"timeout"`
}

type HTTPClient interface {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that you mock http responses, but there's a simpler way to do it that is built in to http.Client. Before calling your http.Client's .Do(), you set its Transport to a custom http.RoundTripper.

I'd prefer to remove this HTTPClient interface and use a custom RoundTripper because it requires less code and because it's standard Go so it will be easier for whoever works on this code later.

https://golang.org/pkg/net/http/#RoundTripper

Copy link
Contributor Author

@SirishaGopigiri SirishaGopigiri Jan 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the comments Reimda. I have written some sample code around RoundTripper. Could you please check?

type transportMock struct {
errorString string
}

func newTransportMock(errorString string) http.RoundTripper {
return &transportMock{
errorString: errorString,
}
}

func (t *transportMock) RoundTrip(r *http.Request) (*http.Response, error) {
return nil, errors.New(t.errorString)
}

func TestAllowHosts(t *testing.T) {

    networkError := "Get http://127.0.0.1:2812/_status?format=xml: " +
                    "read tcp 192.168.10.2:55610->127.0.0.1:2812: " +
                    "read: connection reset by peer"
    r := &Monit{
            Address:  "http://127.0.0.1:2812",
            Username: "test",
            Password: "test",
            client:         &http.Client{}
    }

    var acc testutil.Accumulator

    r.client.Transport = newTransportMock(networkError)

    err := r.Gather(&acc)

    if assert.Error(t, err) {
            assert.Contains(t, err.Error(), "read: connection reset by peer")
    }

}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the idea. Also change Monit.client to be a http.Client, not a *http.Client, so you don't have to explicitly initialize it. I'd probably make type transportMock an empty struct and put the networkError string right in the RoundTrip func. Then you don't need newTransportMock either.

Looks like we already merged this PR. If you want to make a new PR to change this, feel free to add me as a reviewer.

thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the comments. I have raised a new PR. Could you please review?
#6955

athoune pushed a commit to bearstech/telegraf that referenced this pull request Apr 17, 2020
idohalevi pushed a commit to idohalevi/telegraf that referenced this pull request Sep 29, 2020
arstercz pushed a commit to arstercz/telegraf that referenced this pull request Mar 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Plugin suggestion: Monit
4 participants