1
0
mirror of https://github.com/taigrr/wtf synced 2025-01-18 04:03:14 -08:00

Integrate vendored NewRelic dependency (#767)

The NewRelic module relies on yfronto/newrelic, which no longer exists.
yfronto deleted that directory quite awhile ago, and since then it has
been vendored.

But vendoring a missing repository creates problems when trying to
update the vendored code.

This PR brings the yfronto/newrelic code into the mainline.

Signed-off-by: Chris Cummer <chriscummer@me.com>
This commit is contained in:
Chris Cummer
2019-12-01 20:47:02 -08:00
committed by GitHub
parent d9464c4a22
commit 31926fd4a7
37 changed files with 9 additions and 67 deletions

View File

@@ -0,0 +1,75 @@
[![GoDoc](http://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/yfronto/newrelic)
[![Build
status](https://travis-ci.org/yfronto/newrelic.svg)](https://travis-ci.org/yfronto/newrelic)
# New Relic API library for Go
This is a Go library that wraps the [New Relic][1] REST
API. It provides the needed types to interact with the New Relic REST API.
It's still in progress and I haven't finished the entirety of the API, yet. I
plan to finish all GET (read) operations before any POST (create) operations,
and then PUT (update) operations, and, finally, the DELETE operations.
The API documentation can be found from [New Relic][1],
and you'll need an API key (for some operations, an Admin API key is
required).
## USAGE
This library will provide a client object and any operations can be performed
through it. Simply import this library and create a client to get started:
```go
package main
import (
"github.com/yfronto/newrelic"
)
var api_key = "..." // Required
func main() {
// Create the client object
client := newrelic.NewClient(api_key)
// Get the applciation with ID 12345
myApp, err := client.GetApplication(12345)
if err != nil {
// Handle error
}
// Work with the object
fmt.Println(myApp.Name)
// Some operations accept options
opts := &newrelic.AlertEventOptions{
// Only events with "MyProduct" as the product name
Filter: newRelic.AlertEventFilter{
Product: "MyProduct",
},
}
// Get a list of recent events for my product
events, err := client.GetAlertEvents(opts)
if err != nil {
// Handle error
}
// Display each event with some information
for _, e := range events {
fmt.Printf("%d -- %d (%s): %s\n", e.Timestamp, e.Id, e.Priority, e.Description)
}
}
```
## Contributing
As I work to populate all actions, bugs are bound to come up. Feel free to
send me a pull request or just file an issue. Staying up to date with an API
is hard work and I'm happy to accept contributors.
**DISCLAIMER:** *I am in no way affiliated with New Relic and this work is
merely a convenience project for myself with no guarantees. It should be
considered "as-is" with no implication of responsibility. See the included
LICENSE for more details.*
[1]: http://www.newrelic.com

View File

@@ -0,0 +1,59 @@
package newrelic
// AlertCondition describes what triggers an alert for a specific policy.
type AlertCondition struct {
ID int `json:"id,omitempty"`
Type string `json:"type,omitempty"`
Name string `json:"name,omitempty"`
Enabled bool `json:"name,omitempty"`
Entities []string `json:"entities,omitempty"`
Metric string `json:"metric,omitempty"`
RunbookURL string `json:"runbook_url,omitempty"`
Terms []AlertConditionTerm `json:"terms,omitempty"`
UserDefined AlertUserDefined `json:"user_defined,omitempty"`
}
// AlertConditionTerm defines thresholds that trigger an AlertCondition.
type AlertConditionTerm struct {
Duration string `json:"duration,omitempty"`
Operator string `json:"operator,omitempty"`
Priority string `json:"priority,omitempty"`
Threshold string `json:"threshold,omitempty"`
TimeFunction string `json:"time_function,omitempty"`
}
// AlertUserDefined describes user-defined behavior for an AlertCondition.
type AlertUserDefined struct {
Metric string `json:"metric,omitempty"`
ValueFunction string `json:"value_function,omitempty"`
}
// AlertConditionOptions define filters for GetAlertConditions.
type AlertConditionOptions struct {
policyID int
Page int
}
func (o *AlertConditionOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"policy_id": o.policyID,
"page": o.Page,
})
}
// GetAlertConditions will return any AlertCondition defined for a given
// policy, optionally filtered by AlertConditionOptions.
func (c *Client) GetAlertConditions(policy int, options *AlertConditionOptions) ([]AlertCondition, error) {
resp := &struct {
Conditions []AlertCondition `json:"conditions,omitempty"`
}{}
options.policyID = policy
err := c.doGet("alerts_conditions.json", options, resp)
if err != nil {
return nil, err
}
return resp.Conditions, nil
}

View File

@@ -0,0 +1,60 @@
package newrelic
// AlertEvent describes a triggered event.
type AlertEvent struct {
ID int `json:"id,omitempty"`
EventType string `json:"event_type,omitempty"`
Product string `json:"product,omitempty"`
EntityType string `json:"entity_type,omitempty"`
EntityGroupID int `json:"entity_group_id,omitempty"`
EntityID int `json:"entity_id,omitempty"`
Priority string `json:"priority,omitempty"`
Description string `json:"description,omitempty"`
Timestamp int64 `json:"timestamp,omitempty"`
IncidentID int `json:"incident_id"`
}
// AlertEventFilter provides filters for AlertEventOptions when calling
// GetAlertEvents.
type AlertEventFilter struct {
// TODO: New relic restricts these options
Product string
EntityType string
EntityGroupID int
EntityID int
EventType string
}
// AlertEventOptions is an optional means of filtering AlertEvents when
// calling GetAlertEvents.
type AlertEventOptions struct {
Filter AlertEventFilter
Page int
}
func (o *AlertEventOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"filter[product]": o.Filter.Product,
"filter[entity_type]": o.Filter.EntityType,
"filter[entity_group_id]": o.Filter.EntityGroupID,
"filter[entity_id]": o.Filter.EntityID,
"filter[event_type]": o.Filter.EventType,
"page": o.Page,
})
}
// GetAlertEvents will return a slice of recent AlertEvent items triggered,
// optionally filtering by AlertEventOptions.
func (c *Client) GetAlertEvents(options *AlertEventOptions) ([]AlertEvent, error) {
resp := &struct {
RecentEvents []AlertEvent `json:"recent_events,omitempty"`
}{}
err := c.doGet("alerts_events.json", options, resp)
if err != nil {
return nil, err
}
return resp.RecentEvents, nil
}

View File

@@ -0,0 +1,91 @@
package newrelic
type getAlertEventsTestsInput struct {
options *AlertEventOptions
data string
}
type getAlertEventsTestsOutput struct {
data []AlertEvent
err error
}
const (
testAlertEventJSON = `
{
"id": 123,
"event_type": "VIOLATION_OPEN",
"product": "APM",
"entity_type": "Application",
"entity_group_id": 1234,
"entity_id": 12,
"priority": "Warning",
"description": "Test Alert",
"timestamp": 1472355451353,
"incident_id": 23
}
`
)
var (
testAlertEvent = AlertEvent{
ID: 123,
EventType: "VIOLATION_OPEN",
Product: "APM",
EntityType: "Application",
EntityGroupID: 1234,
EntityID: 12,
Priority: "Warning",
Description: "Test Alert",
Timestamp: 1472355451353,
IncidentID: 23,
}
getAlertEventsTests = []struct {
in getAlertEventsTestsInput
out getAlertEventsTestsOutput
}{
{
getAlertEventsTestsInput{
options: nil,
data: `{"recent_events": [` + testAlertEventJSON + `]}`,
},
getAlertEventsTestsOutput{
data: []AlertEvent{
testAlertEvent,
},
err: nil,
},
},
}
alertEventOptionsStringerTests = []struct {
in *AlertEventOptions
out string
}{
{
&AlertEventOptions{},
"",
},
{
nil,
"",
},
{
&AlertEventOptions{
Filter: AlertEventFilter{
Product: "testProduct",
EntityType: "testEntityType",
EntityGroupID: 123,
EntityID: 1234,
EventType: "testEventType",
},
Page: 1,
},
"filter%5Bentity_group_id%5D=123" +
"&filter%5Bentity_id%5D=1234" +
"&filter%5Bentity_type%5D=testEntityType" +
"&filter%5Bevent_type%5D=testEventType" +
"&filter%5Bproduct%5D=testProduct" +
"&page=1",
},
}
)

View File

@@ -0,0 +1,53 @@
package newrelic
import (
"strconv"
"time"
)
// ApplicationDeploymentLinks represents links that apply to an
// ApplicationDeployment.
type ApplicationDeploymentLinks struct {
Application int `json:"application,omitempty"`
}
// ApplicationDeploymentOptions provide a means to filter when calling
// GetApplicationDeployments.
type ApplicationDeploymentOptions struct {
Page int
}
// ApplicationDeployment contains information about a New Relic Application
// Deployment.
type ApplicationDeployment struct {
ID int `json:"id,omitempty"`
Revision string `json:"revision,omitempty"`
Changelog string `json:"changelog,omitempty"`
Description string `json:"description,omitempty"`
User string `json:"user,omitemtpy"`
Timestamp time.Time `json:"timestamp,omitempty"`
Links ApplicationDeploymentLinks `json:"links,omitempty"`
}
// GetApplicationDeployments returns a slice of New Relic Application
// Deployments.
func (c *Client) GetApplicationDeployments(id int, opt *ApplicationDeploymentOptions) ([]ApplicationDeployment, error) {
resp := &struct {
Deployments []ApplicationDeployment `json:"deployments,omitempty"`
}{}
path := "applications/" + strconv.Itoa(id) + "/deployments.json"
err := c.doGet(path, opt, resp)
if err != nil {
return nil, err
}
return resp.Deployments, nil
}
func (o *ApplicationDeploymentOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"page": o.Page,
})
}

View File

@@ -0,0 +1,38 @@
package newrelic
import (
"fmt"
)
// GetApplicationHostMetrics will return a slice of Metric items for a
// particular Application ID's Host ID, optionally filtering by
// MetricsOptions.
func (c *Client) GetApplicationHostMetrics(appID, hostID int, options *MetricsOptions) ([]Metric, error) {
mc := NewMetricClient(c)
return mc.GetMetrics(
fmt.Sprintf(
"applications/%d/hosts/%d/metrics.json",
appID,
hostID,
),
options,
)
}
// GetApplicationHostMetricData will return all metric data for a particular
// application's host and slice of metric names, optionally filtered by
// MetricDataOptions.
func (c *Client) GetApplicationHostMetricData(appID, hostID int, names []string, options *MetricDataOptions) (*MetricDataResponse, error) {
mc := NewMetricClient(c)
return mc.GetMetricData(
fmt.Sprintf(
"applications/%d/hosts/%d/metrics/data.json",
appID,
hostID,
),
names,
options,
)
}

View File

@@ -0,0 +1,94 @@
package newrelic
import (
"strconv"
)
// ApplicationHostSummary describes an Application's host.
type ApplicationHostSummary struct {
ApdexScore float64 `json:"apdex_score,omitempty"`
ErrorRate float64 `json:"error_rate,omitempty"`
InstanceCount int `json:"instance_count,omitempty"`
ResponseTime float64 `json:"response_time,omitempty"`
Throughput float64 `json:"throughput,omitempty"`
}
// ApplicationHostEndUserSummary describes the end user summary component of
// an ApplicationHost.
type ApplicationHostEndUserSummary struct {
ResponseTime float64 `json:"response_time,omitempty"`
Throughput float64 `json:"throughput,omitempty"`
ApdexScore float64 `json:"apdex_score,omitempty"`
}
// ApplicationHostLinks list IDs associated with an ApplicationHost.
type ApplicationHostLinks struct {
Application int `json:"application,omitempty"`
ApplicationInstances []int `json:"application_instances,omitempty"`
Server int `json:"server,omitempty"`
}
// ApplicationHost describes a New Relic Application Host.
type ApplicationHost struct {
ApplicationName string `json:"application_name,omitempty"`
ApplicationSummary ApplicationHostSummary `json:"application_summary,omitempty"`
HealthStatus string `json:"health_status,omitempty"`
Host string `json:"host,omitempty"`
ID int `json:"idomitempty"`
Language string `json:"language,omitempty"`
Links ApplicationHostLinks `json:"links,omitempty"`
EndUserSummary ApplicationHostEndUserSummary `json:"end_user_summary,omitempty"`
}
// ApplicationHostsFilter provides a means to filter requests through
// ApplicationHostsOptions when calling GetApplicationHosts.
type ApplicationHostsFilter struct {
Hostname string
IDs []int
}
// ApplicationHostsOptions provide a means to filter results when calling
// GetApplicationHosts.
type ApplicationHostsOptions struct {
Filter ApplicationHostsFilter
Page int
}
// GetApplicationHosts returns a slice of New Relic Application Hosts,
// optionally filtering by ApplicationHostOptions.
func (c *Client) GetApplicationHosts(id int, options *ApplicationHostsOptions) ([]ApplicationHost, error) {
resp := &struct {
ApplicationHosts []ApplicationHost `json:"application_hosts,omitempty"`
}{}
path := "applications/" + strconv.Itoa(id) + "/hosts.json"
err := c.doGet(path, options, resp)
if err != nil {
return nil, err
}
return resp.ApplicationHosts, nil
}
// GetApplicationHost returns a single Application Host associated with the
// given application host ID and host ID.
func (c *Client) GetApplicationHost(appID, hostID int) (*ApplicationHost, error) {
resp := &struct {
ApplicationHost ApplicationHost `json:"application_host,omitempty"`
}{}
path := "applications/" + strconv.Itoa(appID) + "/hosts/" + strconv.Itoa(hostID) + ".json"
err := c.doGet(path, nil, resp)
if err != nil {
return nil, err
}
return &resp.ApplicationHost, nil
}
func (o *ApplicationHostsOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"filter[hostname]": o.Filter.Hostname,
"filter[ids]": o.Filter.IDs,
"page": o.Page,
})
}

View File

@@ -0,0 +1,38 @@
package newrelic
import (
"fmt"
)
// GetApplicationInstanceMetrics will return a slice of Metric items for a
// particular Application ID's instance ID, optionally filtering by
// MetricsOptions.
func (c *Client) GetApplicationInstanceMetrics(appID, instanceID int, options *MetricsOptions) ([]Metric, error) {
mc := NewMetricClient(c)
return mc.GetMetrics(
fmt.Sprintf(
"applications/%d/instances/%d/metrics.json",
appID,
instanceID,
),
options,
)
}
// GetApplicationInstanceMetricData will return all metric data for a
// particular application's instance and slice of metric names, optionally
// filtered by MetricDataOptions.
func (c *Client) GetApplicationInstanceMetricData(appID, instanceID int, names []string, options *MetricDataOptions) (*MetricDataResponse, error) {
mc := NewMetricClient(c)
return mc.GetMetricData(
fmt.Sprintf(
"applications/%d/instances/%d/metrics/data.json",
appID,
instanceID,
),
names,
options,
)
}

View File

@@ -0,0 +1,94 @@
package newrelic
import (
"strconv"
)
// ApplicationInstanceSummary describes an Application's instance.
type ApplicationInstanceSummary struct {
ResponseTime float64 `json:"response_time,omitempty"`
Throughput float64 `json:"throughput,omitempty"`
ErrorRate float64 `json:"error_rate,omitempty"`
ApdexScore float64 `json:"apdex_score,omitempty"`
InstanceCount int `json:"instance_count,omitempty"`
}
// ApplicationInstanceEndUserSummary describes the end user summary component
// of an ApplicationInstance.
type ApplicationInstanceEndUserSummary struct {
ResponseTime float64 `json:"response_time,omitempty"`
Throughput float64 `json:"throughput,omitempty"`
ApdexScore float64 `json:"apdex_score,omitempty"`
}
// ApplicationInstanceLinks lists IDs associated with an ApplicationInstances.
type ApplicationInstanceLinks struct {
Application int `json:"application,omitempty"`
ApplicationHost int `json:"application_host,omitempty"`
Server int `json:"server,omitempty"`
}
// ApplicationInstance describes a New Relic Application instance.
type ApplicationInstance struct {
ID int `json:"id,omitempty"`
ApplicationName string `json:"application_name,omitempty"`
Host string `json:"host,omitempty"`
Port int `json:"port,omitempty"`
Language string `json:"language,omitempty"`
HealthStatus string `json:"health_status,omitempty"`
ApplicationSummary ApplicationInstanceSummary `json:"application_summary,omitempty"`
EndUserSummary ApplicationInstanceEndUserSummary `json:"end_user_summary,omitempty"`
Links ApplicationInstanceLinks `json:"links,omitempty"`
}
// ApplicationInstancesFilter provides a means to filter requests through
// ApplicationInstancesOptions when calling GetApplicationInstances.
type ApplicationInstancesFilter struct {
Hostname string
IDs []int
}
// ApplicationInstancesOptions provides a means to filter results when calling
// GetApplicationInstances.
type ApplicationInstancesOptions struct {
Filter ApplicationInstancesFilter
Page int
}
// GetApplicationInstances returns a slice of New Relic Application Instances,
// optionall filtering by ApplicationInstancesOptions.
func (c *Client) GetApplicationInstances(appID int, options *ApplicationInstancesOptions) ([]ApplicationInstance, error) {
resp := &struct {
ApplicationInstances []ApplicationInstance `json:"application_instances,omitempty"`
}{}
path := "applications/" + strconv.Itoa(appID) + "/instances.json"
err := c.doGet(path, options, resp)
if err != nil {
return nil, err
}
return resp.ApplicationInstances, nil
}
// GetApplicationInstance returns a single Application Instance associated
// with the given application ID and instance ID
func (c *Client) GetApplicationInstance(appID, instanceID int) (*ApplicationInstance, error) {
resp := &struct {
ApplicationInstance ApplicationInstance `json:"application_instance,omitempty"`
}{}
path := "applications/" + strconv.Itoa(appID) + "/instances/" + strconv.Itoa(instanceID) + ".json"
err := c.doGet(path, nil, resp)
if err != nil {
return nil, err
}
return &resp.ApplicationInstance, nil
}
func (o *ApplicationInstancesOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"filter[hostname]": o.Filter.Hostname,
"filter[ids]": o.Filter.IDs,
"page": o.Page,
})
}

View File

@@ -0,0 +1,36 @@
package newrelic
import (
"fmt"
)
// GetApplicationMetrics will return a slice of Metric items for a
// particular Application ID, optionally filtering by
// MetricsOptions.
func (c *Client) GetApplicationMetrics(id int, options *MetricsOptions) ([]Metric, error) {
mc := NewMetricClient(c)
return mc.GetMetrics(
fmt.Sprintf(
"applications/%d/metrics.json",
id,
),
options,
)
}
// GetApplicationMetricData will return all metric data for a particular
// application and slice of metric names, optionally filtered by
// MetricDataOptions.
func (c *Client) GetApplicationMetricData(id int, names []string, options *MetricDataOptions) (*MetricDataResponse, error) {
mc := NewMetricClient(c)
return mc.GetMetricData(
fmt.Sprintf(
"applications/%d/metrics/data.json",
id,
),
names,
options,
)
}

View File

@@ -0,0 +1,175 @@
package newrelic
type getApplicationMetricsTestsInput struct {
id int
options *MetricsOptions
data string
}
type getApplicationMetricsTestsOutput struct {
data []Metric
err error
}
type getApplicationMetricDataTestsInput struct {
id int
Names []string
options *MetricDataOptions
data string
}
type getApplicationMetricDataTestsOutput struct {
data *MetricDataResponse
err error
}
const (
testApplicationMetricJSON = `
{
"name": "testMetric",
"values": [
"testValue1",
"testValue2"
]
}
`
)
var (
testApplicationMetric = Metric{
Name: "testMetric",
Values: []string{"testValue1", "testValue2"},
}
getApplicaitonMetricsTests = []struct {
in getApplicationMetricsTestsInput
out getApplicationMetricsTestsOutput
}{
{
getApplicationMetricsTestsInput{
id: 123,
options: nil,
data: `{"metrics": [` +
testApplicationMetricJSON + `,` +
testApplicationMetricJSON +
`]}`,
},
getApplicationMetricsTestsOutput{
data: []Metric{
testApplicationMetric,
testApplicationMetric,
},
err: nil,
},
},
}
applicationMetricOptionsStringerTests = []struct {
in *MetricsOptions
out string
}{
{
&MetricsOptions{},
"",
},
{
nil,
"",
},
{
&MetricsOptions{
Name: "testName",
Page: 5,
},
"name=testName" +
"&page=5",
},
}
applicationMetricDataOptionsStringerTests = []struct {
in *MetricDataOptions
out string
}{
{
&MetricDataOptions{},
"",
},
{
nil,
"",
},
{
&MetricDataOptions{
Names: Array{[]string{"test1", "test2"}},
Values: Array{[]string{"value1", "value2"}},
From: testTime,
To: testTime,
Period: 123,
Summarize: true,
Raw: true,
},
"from=" + testTimeStringEscaped +
"&names%5B%5D=test1" +
"&names%5B%5D=test2" +
"&period=123" +
"&raw=true" +
"&summarize=true" +
"&to=" + testTimeStringEscaped +
"&values%5B%5D=value1&values%5B%5D=value2",
},
}
testApplicationMetricDataJSON = `
{
"metric_data": {
"from": "` + testTimeRawString + `",
"to": "` + testTimeRawString + `",
"metrics_found": ["name1"],
"metrics_not_found": ["name2"],
"metrics": [
{
"name": "testName",
"timeslices": [
{
"from": "` + testTimeRawString + `",
"to": "` + testTimeRawString + `",
"values": {"testVal": 1.234}
}
]
}
]
}
}
`
testApplicationMetricData = MetricData{
Name: "testName",
Timeslices: []MetricTimeslice{
MetricTimeslice{
From: testTime,
To: testTime,
Values: map[string]float64{
"testVal": 1.234,
},
},
},
}
getApplicaitonMetricDataTests = []struct {
in getApplicationMetricDataTestsInput
out getApplicationMetricDataTestsOutput
}{
{
getApplicationMetricDataTestsInput{
id: 1234,
Names: []string{"name1", "name2"},
options: &MetricDataOptions{},
data: testApplicationMetricDataJSON,
},
getApplicationMetricDataTestsOutput{
data: &MetricDataResponse{
From: testTime,
To: testTime,
MetricsFound: []string{"name1"},
MetricsNotFound: []string{"name2"},
Metrics: []MetricData{testApplicationMetricData},
},
err: nil,
},
},
}
)

View File

@@ -0,0 +1,111 @@
package newrelic
import (
"strconv"
"time"
)
// ApplicationSummary describes the brief summary component of an Application.
type ApplicationSummary struct {
ResponseTime float64 `json:"response_time,omitempty"`
Throughput float64 `json:"throughput,omitempty"`
ErrorRate float64 `json:"error_rate,omitempty"`
ApdexTarget float64 `json:"apdex_target,omitempty"`
ApdexScore float64 `json:"apdex_score,omitempty"`
HostCount int `json:"host_count,omitempty"`
InstanceCount int `json:"instance_count,omitempty"`
ConcurrentInstanceCount int `json:"concurrent_instance_count,omitempty"`
}
// EndUserSummary describes the end user summary component of an Application.
type EndUserSummary struct {
ResponseTime float64 `json:"response_time,omitempty"`
Throughput float64 `json:"throughput,omitempty"`
ApdexTarget float64 `json:"apdex_target,omitempty"`
ApdexScore float64 `json:"apdex_score,omitempty"`
}
// Settings describe settings for an Application.
type Settings struct {
AppApdexThreshold float64 `json:"app_apdex_threshold,omitempty"`
EndUserApdexThreshold float64 `json:"end_user_apdex_threshold,omitempty"`
EnableRealUserMonitoring bool `json:"enable_real_user_monitoring,omitempty"`
UseServerSideConfig bool `json:"use_server_side_config,omitempty"`
}
// Links list IDs associated with an Application.
type Links struct {
Servers []int `json:"servers,omitempty"`
ApplicationHosts []int `json:"application_hosts,omitempty"`
ApplicationInstances []int `json:"application_instances,omitempty"`
AlertPolicy int `json:"alert_policy,omitempty"`
}
// Application describes a New Relic Application.
type Application struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Language string `json:"language,omitempty"`
HealthStatus string `json:"health_status,omitempty"`
Reporting bool `json:"reporting,omitempty"`
LastReportedAt time.Time `json:"last_reported_at,omitempty"`
ApplicationSummary ApplicationSummary `json:"application_summary,omitempty"`
EndUserSummary EndUserSummary `json:"end_user_summary,omitempty"`
Settings Settings `json:"settings,omitempty"`
Links Links `json:"links,omitempty"`
}
// ApplicationFilter provides a means to filter requests through
// ApplicaitonOptions when calling GetApplications.
type ApplicationFilter struct {
Name string
Host string
IDs []int
Language string
}
// ApplicationOptions provides a means to filter results when calling
// GetApplicaitons.
type ApplicationOptions struct {
Filter ApplicationFilter
Page int
}
func (o *ApplicationOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"filter[name]": o.Filter.Name,
"filter[host]": o.Filter.Host,
"filter[ids]": o.Filter.IDs,
"filter[language]": o.Filter.Language,
"page": o.Page,
})
}
// GetApplications returns a slice of New Relic Applications, optionally
// filtering by ApplicationOptions.
func (c *Client) GetApplications(options *ApplicationOptions) ([]Application, error) {
resp := &struct {
Applications []Application `json:"applications,omitempty"`
}{}
err := c.doGet("applications.json", options, resp)
if err != nil {
return nil, err
}
return resp.Applications, nil
}
// GetApplication returns a single Application associated with a given ID.
func (c *Client) GetApplication(id int) (*Application, error) {
resp := &struct {
Application Application `json:"application,omitempty"`
}{}
path := "applications/" + strconv.Itoa(id) + ".json"
err := c.doGet(path, nil, resp)
if err != nil {
return nil, err
}
return &resp.Application, nil
}

View File

@@ -0,0 +1,165 @@
package newrelic
type getApplicationsTestsInput struct {
options *ApplicationOptions
data string
}
type getApplicationsTestsOutput struct {
data []Application
err error
}
type getApplicationTestsInput struct {
id int
data string
}
type getApplicationTestsOutput struct {
data *Application
err error
}
var (
testApplicationJSON = `
{
"application_summary": {
"apdex_score": 1.0,
"apdex_target": 0.5,
"error_rate": 0.0,
"host_count": 1,
"instance_count": 1,
"response_time": 0.263,
"throughput": 12.3
},
"end_user_summary": {
"response_time": 0.263,
"throughput": 12.3,
"apdex_target": 0.5,
"apdex_score": 1
},
"health_status": "green",
"id": 12345,
"language": "java",
"last_reported_at": "` + testTimeRawString + `",
"links": {
"alert_policy": 123,
"application_hosts": [
1234567
],
"application_instances": [
1234568
],
"servers": [
54321
]
},
"name": "test.example.com",
"reporting": true,
"settings": {
"app_apdex_threshold": 0.5,
"enable_real_user_monitoring": true,
"end_user_apdex_threshold": 1.0,
"use_server_side_config": false
}
}
`
testApplication = Application{
ID: 12345,
Name: "test.example.com",
Language: "java",
HealthStatus: "green",
Reporting: true,
LastReportedAt: testTime,
ApplicationSummary: ApplicationSummary{
ResponseTime: 0.263,
Throughput: 12.3,
ErrorRate: 0,
ApdexTarget: 0.5,
ApdexScore: 1,
HostCount: 1,
InstanceCount: 1,
ConcurrentInstanceCount: 0,
},
EndUserSummary: EndUserSummary{
ResponseTime: 0.263,
Throughput: 12.3,
ApdexTarget: 0.5,
ApdexScore: 1,
},
Settings: Settings{
AppApdexThreshold: 0.5,
EndUserApdexThreshold: 1,
EnableRealUserMonitoring: true,
UseServerSideConfig: false,
},
Links: Links{
Servers: []int{54321},
ApplicationHosts: []int{1234567},
ApplicationInstances: []int{1234568},
AlertPolicy: 123,
},
}
testApplications = []Application{
testApplication,
testApplication,
}
getApplicationTests = []struct {
in getApplicationTestsInput
out getApplicationTestsOutput
}{
{
getApplicationTestsInput{
id: 12345,
data: `{ "application":` + testApplicationJSON + `}`,
},
getApplicationTestsOutput{
data: &testApplication,
},
},
}
getApplicationsTests = []struct {
in getApplicationsTestsInput
out getApplicationsTestsOutput
}{
{
getApplicationsTestsInput{
options: nil,
data: `{"applications":[` + testApplicationJSON + "," + testApplicationJSON + "]}",
},
getApplicationsTestsOutput{
data: testApplications,
err: nil,
},
},
}
applicationOptionsStringerTests = []struct {
in *ApplicationOptions
out string
}{
{
&ApplicationOptions{},
"",
},
{
&ApplicationOptions{
Filter: ApplicationFilter{
Name: "testName",
Host: "testHost",
IDs: []int{123, 456},
Language: "java",
},
Page: 5,
},
`filter%5Bhost%5D=testHost` +
`&filter%5Bids%5D=123%2C456` +
`&filter%5Blanguage%5D=java` +
`&filter%5Bname%5D=testName` +
`&page=5`,
},
{
nil,
"",
},
}
)

View File

@@ -0,0 +1,11 @@
package newrelic
// An Array is a type expected by the NewRelic API that differs from a comma-
// separated list. When passing GET params that expect an 'Array' type with
// one to many values, the expected format is "key=val1&key=val2" but an
// argument with zero to many values is of the form "key=val1,val2", and
// neither can be used in the other's place, so we have to differentiate
// somehow.
type Array struct {
arr []string
}

View File

@@ -0,0 +1,48 @@
package newrelic
// BrowserApplicationsFilter is the filtering component of
// BrowserApplicationsOptions
type BrowserApplicationsFilter struct {
Name string
IDs []int
}
// BrowserApplicationsOptions provides a filtering mechanism for
// GetBrowserApplications.
type BrowserApplicationsOptions struct {
Filter BrowserApplicationsFilter
Page int
}
// BrowserApplication describes a New Relic Browser Application.
type BrowserApplication struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
BrowserMonitoringKey string `json:"browser_monitoring_key,omitempty"`
LoaderScript string `json:"loader_script,omitempty"`
}
// GetBrowserApplications will return a slice of New Relic Browser
// Applications, optionally filtered by BrowserApplicationsOptions.
func (c *Client) GetBrowserApplications(opt *BrowserApplicationsOptions) ([]BrowserApplication, error) {
resp := &struct {
BrowserApplications []BrowserApplication `json:"browser_applications,omitempty"`
}{}
path := "browser_applications.json"
err := c.doGet(path, opt, resp)
if err != nil {
return nil, err
}
return resp.BrowserApplications, nil
}
func (o *BrowserApplicationsOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"filter[name]": o.Filter.Name,
"filter[ids]": o.Filter.IDs,
"page": o.Page,
})
}

View File

@@ -0,0 +1,17 @@
package newrelic
import (
"net/url"
"time"
)
const (
testAPIKey = "test_api_key"
testTimeRawString = "2016-01-20T20:29:38Z"
)
var (
testTime, _ = time.Parse(time.RFC3339, testTimeRawString)
testTimeString = testTime.String()
testTimeStringEscaped = url.QueryEscape(testTimeString)
)

View File

@@ -0,0 +1,34 @@
package newrelic
import (
"fmt"
)
// GetComponentMetrics will return a slice of Metric items for a
// particular Component ID, optionally filtered by MetricsOptions.
func (c *Client) GetComponentMetrics(id int, options *MetricsOptions) ([]Metric, error) {
mc := NewMetricClient(c)
return mc.GetMetrics(
fmt.Sprintf(
"components/%d/metrics.json",
id,
),
options,
)
}
// GetComponentMetricData will return all metric data for a particular
// component, optionally filtered by MetricDataOptions.
func (c *Client) GetComponentMetricData(id int, names []string, options *MetricDataOptions) (*MetricDataResponse, error) {
mc := NewMetricClient(c)
return mc.GetMetricData(
fmt.Sprintf(
"components/%d/metrics/data.json",
id,
),
names,
options,
)
}

View File

@@ -0,0 +1,100 @@
package newrelic
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
func (c *Client) doGet(path string, params fmt.Stringer, out interface{}) error {
var s string
if params != nil {
s = params.String()
}
r := strings.NewReader(s)
req, err := http.NewRequest("GET", c.url.String()+path, r)
if err != nil {
return err
}
req.Header.Add("X-Api-Key", c.apiKey)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
return c.doRequest(req, out)
}
func (c *Client) doRequest(req *http.Request, out interface{}) error {
resp, err := c.httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return fmt.Errorf("newrelic http error (%s): %s", resp.Status, b)
}
if len(b) == 0 {
b = []byte{'{', '}'}
}
err = json.Unmarshal(b, &out)
if err != nil {
return err
}
return nil
}
func encodeGetParams(params map[string]interface{}) string {
s := url.Values{}
for k, v := range params {
switch v.(type) {
case string:
val := v.(string)
if val != "" {
s.Add(k, val)
}
case int:
val := v.(int)
// TODO: Zero values versus not defined
if val != 0 {
s.Add(k, strconv.Itoa(val))
}
case []string:
val := v.([]string)
if len(val) != 0 {
s.Add(k, strings.Join(val, ","))
}
case []int:
val := v.([]int)
arr := []string{}
for _, v := range val {
arr = append(arr, strconv.Itoa(v))
}
if len(arr) != 0 {
s.Add(k, strings.Join(arr, ","))
}
case time.Time:
val := v.(time.Time)
if !val.IsZero() {
s.Add(k, val.String())
}
case Array:
val := v.(Array)
for _, v := range val.arr {
s.Add(k, v)
}
case bool:
if v.(bool) {
s.Add(k, "true")
}
default:
s.Add(k, fmt.Sprintf("%v", v))
}
}
return s.Encode()
}

View File

@@ -0,0 +1,119 @@
package newrelic
import (
"errors"
"net/http"
"strings"
)
type testJSONInterface struct {
data string `json:"data"id,omitempty"`
}
type testParamsInterface struct {
data string
}
type doGetTestsInput struct {
path string
params *testParamsInterface
out testJSONInterface
status int
data string
}
type doGetTestsOutput struct {
data testJSONInterface
err error
}
type doRequestTestsInput struct {
req *http.Request
out testJSONInterface
status int
data string
}
type doRequestTestOutput struct {
data testJSONInterface
err error
}
var (
doGetTests = []struct {
in doGetTestsInput
out doGetTestsOutput
}{
{
doGetTestsInput{
path: "somePath",
params: &testParamsInterface{"testData"},
out: testJSONInterface{"testData"},
status: 200,
data: `{"data": "testStructData"}`,
},
doGetTestsOutput{
data: testJSONInterface{"testData"},
err: nil,
},
},
{
doGetTestsInput{
status: 404,
data: "Not Found",
},
doGetTestsOutput{
err: errors.New("newrelic http error (404 Not Found): Not Found"),
},
},
}
testRequest, _ = http.NewRequest("GET", "http://testPath",
strings.NewReader("testBody"))
doRequestTests = []struct {
in doRequestTestsInput
out doRequestTestOutput
}{
{
doRequestTestsInput{
req: testRequest,
out: testJSONInterface{"testData"},
status: 200,
data: `{"data": "testStructData"}`,
},
doRequestTestOutput{
data: testJSONInterface{"testData"},
err: nil,
},
},
}
encodeGetParamsTests = []struct {
in map[string]interface{}
out string
}{
{
map[string]interface{}{
"testInt": 5,
"testString": "test",
"testStringSlice": []string{"test1", "test2"},
"testArray": Array{[]string{"test1", "test2"}},
"testTime": testTime,
},
"testArray=test1" +
"&testArray=test2" +
"&testInt=5" +
"&testString=test" +
"&testStringSlice=test1%2Ctest2" +
"&testTime=" + testTimeStringEscaped,
},
{
map[string]interface{}{
"unexpectedType": map[string]string{"unexpected": "type"},
},
"unexpectedType=map%5Bunexpected%3Atype%5D",
},
}
)
func (m *testParamsInterface) String() string {
return "data=testData"
}

View File

@@ -0,0 +1,76 @@
package newrelic
import (
"strconv"
"time"
)
// KeyTransactionsFilter is the filtering component of KeyTransactionsOptions.
type KeyTransactionsFilter struct {
Name string
IDs []int
}
// KeyTransactionsOptions provides a filtering mechanism for GetKeyTransactions.
type KeyTransactionsOptions struct {
Filter KeyTransactionsFilter
Page int
}
// KeyTransactionLinks link KeyTransactions to the objects to which they
// pertain.
type KeyTransactionLinks struct {
Application int `json:"application,omitempty"`
}
// KeyTransaction represents a New Relic Key Transaction.
type KeyTransaction struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
TransactionName string `json:"transaction_name,omitempty"`
HealthStatus string `json:"health_status,omitempty"`
Reporting bool `json:"reporting,omitempty"`
LastReportedAt time.Time `json:"last_reported_at,omitempty"`
ApplicationSummary ApplicationSummary `json:"application_summary,omitempty"`
EndUserSummary EndUserSummary `json:"end_user_summary,omitempty"`
Links KeyTransactionLinks `json:"links,omitempty"`
}
// GetKeyTransactions will return a slice of New Relic Key Transactions,
// optionally filtered by KeyTransactionsOptions.
func (c *Client) GetKeyTransactions(opt *KeyTransactionsOptions) ([]KeyTransaction, error) {
resp := &struct {
KeyTransactions []KeyTransaction `json:"key_transactions,omitempty"`
}{}
path := "key_transactions.json"
err := c.doGet(path, opt, resp)
if err != nil {
return nil, err
}
return resp.KeyTransactions, nil
}
// GetKeyTransaction will return a single New Relic Key Transaction for the
// given id.
func (c *Client) GetKeyTransaction(id int) (*KeyTransaction, error) {
resp := &struct {
KeyTransaction *KeyTransaction `json:"key_transaction,omitempty"`
}{}
path := "key_transactions/" + strconv.Itoa(id) + ".json"
err := c.doGet(path, nil, resp)
if err != nil {
return nil, err
}
return resp.KeyTransaction, nil
}
func (o *KeyTransactionsOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"filter[name]": o.Filter.Name,
"filter[ids]": o.Filter.IDs,
"page": o.Page,
})
}

View File

@@ -0,0 +1,78 @@
package newrelic
import (
"strconv"
)
// LegacyAlertPolicyLinks describes object links for Alert Policies.
type LegacyAlertPolicyLinks struct {
NotificationChannels []int `json:"notification_channels,omitempty"`
Servers []int `json:"servers,omitempty"`
}
// LegacyAlertPolicyCondition describes conditions that trigger an LegacyAlertPolicy.
type LegacyAlertPolicyCondition struct {
ID int `json:"id,omitempty"`
Enabled bool `json:"enabled,omitempty"`
Severity string `json:"severity,omitempty"`
Threshold float64 `json:"threshold,omitempty"`
TriggerMinutes int `json:"trigger_minutes,omitempty"`
Type string `json:"type,omitempty"`
}
// LegacyAlertPolicy describes a New Relic alert policy.
type LegacyAlertPolicy struct {
Conditions []LegacyAlertPolicyCondition `json:"conditions,omitempty"`
Enabled bool `json:"enabled,omitempty"`
ID int `json:"id,omitempty"`
Links LegacyAlertPolicyLinks `json:"links,omitempty"`
IncidentPreference string `json:"incident_preference,omitempty"`
Name string `json:"name,omitempty"`
}
// LegacyAlertPolicyFilter provides filters for LegacyAlertPolicyOptions.
type LegacyAlertPolicyFilter struct {
Name string
}
// LegacyAlertPolicyOptions is an optional means of filtering when calling
// GetLegacyAlertPolicies.
type LegacyAlertPolicyOptions struct {
Filter LegacyAlertPolicyFilter
Page int
}
func (o *LegacyAlertPolicyOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"filter[name]": o.Filter.Name,
"page": o.Page,
})
}
// GetLegacyAlertPolicy will return the LegacyAlertPolicy with particular ID.
func (c *Client) GetLegacyAlertPolicy(id int) (*LegacyAlertPolicy, error) {
resp := &struct {
LegacyAlertPolicy *LegacyAlertPolicy `json:"alert_policy,omitempty"`
}{}
err := c.doGet("alert_policies/"+strconv.Itoa(id)+".json", nil, resp)
if err != nil {
return nil, err
}
return resp.LegacyAlertPolicy, nil
}
// GetLegacyAlertPolicies will return a slice of LegacyAlertPolicy items,
// optionally filtering by LegacyAlertPolicyOptions.
func (c *Client) GetLegacyAlertPolicies(options *LegacyAlertPolicyOptions) ([]LegacyAlertPolicy, error) {
resp := &struct {
LegacyAlertPolicies []LegacyAlertPolicy `json:"alert_policies,omitempty"`
}{}
err := c.doGet("alert_policies.json", options, resp)
if err != nil {
return nil, err
}
return resp.LegacyAlertPolicies, nil
}

View File

@@ -0,0 +1,48 @@
/*
* NewRelic API for Go
*
* Please see the included LICENSE file for licensing information.
*
* Copyright 2016 by authors and contributors.
*/
package newrelic
import (
"net/http"
"net/url"
"time"
)
const (
// defaultAPIURL is the default base URL for New Relic's latest API.
defaultAPIURL = "https://api.newrelic.com/v2/"
// defaultTimeout is the default timeout for the http.Client used.
defaultTimeout = 5 * time.Second
)
// Client provides a set of methods to interact with the New Relic API.
type Client struct {
apiKey string
httpClient *http.Client
url *url.URL
}
// NewWithHTTPClient returns a new Client object for interfacing with the New
// Relic API, allowing for override of the http.Client object.
func NewWithHTTPClient(apiKey string, client *http.Client) *Client {
u, err := url.Parse(defaultAPIURL)
if err != nil {
panic(err)
}
return &Client{
apiKey: apiKey,
httpClient: client,
url: u,
}
}
// NewClient returns a new Client object for interfacing with the New Relic API.
func NewClient(apiKey string) *Client {
return NewWithHTTPClient(apiKey, &http.Client{Timeout: defaultTimeout})
}

View File

@@ -0,0 +1,128 @@
package newrelic
import (
"time"
)
// Metric describes a New Relic metric.
type Metric struct {
Name string `json:"name,omitempty"`
Values []string `json:"values,omitempty"`
}
// MetricsOptions options allow filtering when getting lists of metric names
// associated with an entity.
type MetricsOptions struct {
Name string
Page int
}
// MetricTimeslice describes the period to which a Metric pertains.
type MetricTimeslice struct {
From time.Time `json:"from,omitempty"`
To time.Time `json:"to,omitempty"`
Values map[string]float64 `json:"values,omitempty"`
}
// MetricData describes the data for a particular metric.
type MetricData struct {
Name string `json:"name,omitempty"`
Timeslices []MetricTimeslice `json:"timeslices,omitempty"`
}
// MetricDataOptions allow filtering when getting data about a particular set
// of New Relic metrics.
type MetricDataOptions struct {
Names Array
Values Array
From time.Time
To time.Time
Period int
Summarize bool
Raw bool
}
// MetricDataResponse is the response received from New Relic for any request
// for metric data.
type MetricDataResponse struct {
From time.Time `json:"from,omitempty"`
To time.Time `json:"to,omitempty"`
MetricsNotFound []string `json:"metrics_not_found,omitempty"`
MetricsFound []string `json:"metrics_found,omitempty"`
Metrics []MetricData `json:"metrics,omitempty"`
}
func (o *MetricsOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"name": o.Name,
"page": o.Page,
})
}
func (o *MetricDataOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"names[]": o.Names,
"values[]": o.Values,
"from": o.From,
"to": o.To,
"period": o.Period,
"summarize": o.Summarize,
"raw": o.Raw,
})
}
// MetricClient implements a generic New Relic metrics client.
// This is used as a general client for fetching metric names and data.
type MetricClient struct {
newRelicClient *Client
}
// NewMetricClient creates and returns a new MetricClient.
func NewMetricClient(newRelicClient *Client) *MetricClient {
return &MetricClient{
newRelicClient: newRelicClient,
}
}
// GetMetrics is a generic function for fetching a list of available metrics
// from different parts of New Relic.
// Example: Application metrics, Component metrics, etc.
func (mc *MetricClient) GetMetrics(path string, options *MetricsOptions) ([]Metric, error) {
resp := &struct {
Metrics []Metric `json:"metrics,omitempty"`
}{}
err := mc.newRelicClient.doGet(path, options, resp)
if err != nil {
return nil, err
}
return resp.Metrics, nil
}
// GetMetricData is a generic function for fetching data for a specific metric.
// from different parts of New Relic.
// Example: Application metric data, Component metric data, etc.
func (mc *MetricClient) GetMetricData(path string, names []string, options *MetricDataOptions) (*MetricDataResponse, error) {
resp := &struct {
MetricData MetricDataResponse `json:"metric_data,omitempty"`
}{}
if options == nil {
options = &MetricDataOptions{}
}
options.Names = Array{names}
err := mc.newRelicClient.doGet(path, options, resp)
if err != nil {
return nil, err
}
return &resp.MetricData, nil
}

View File

@@ -0,0 +1,36 @@
package newrelic
import (
"fmt"
)
// GetMobileApplicationMetrics will return a slice of Metric items for a
// particular MobileAplication ID, optionally filtering by
// MetricsOptions.
func (c *Client) GetMobileApplicationMetrics(id int, options *MetricsOptions) ([]Metric, error) {
mc := NewMetricClient(c)
return mc.GetMetrics(
fmt.Sprintf(
"mobile_applications/%d/metrics.json",
id,
),
options,
)
}
// GetMobileApplicationMetricData will return all metric data for a particular
// MobileAplication and slice of metric names, optionally filtered by
// MetricDataOptions.
func (c *Client) GetMobileApplicationMetricData(id int, names []string, options *MetricDataOptions) (*MetricDataResponse, error) {
mc := NewMetricClient(c)
return mc.GetMetricData(
fmt.Sprintf(
"mobile_applications/%d/metrics/data.json",
id,
),
names,
options,
)
}

View File

@@ -0,0 +1,61 @@
package newrelic
import (
"strconv"
)
// MobileApplicationSummary describes an Application's host.
type MobileApplicationSummary struct {
ActiveUsers int `json:"active_users,omitempty"`
LaunchCount int `json:"launch_count,omitempty"`
Throughput float64 `json:"throughput,omitempty"`
ResponseTime float64 `json:"response_time,omitempty"`
CallsPerSession float64 `json:"calls_per_session,omitempty"`
InteractionTime float64 `json:"interaction_time,omitempty"`
FailedCallRate float64 `json:"failed_call_rate,omitempty"`
RemoteErrorRate float64 `json:"remote_error_rate"`
}
// MobileApplicationCrashSummary describes a MobileApplication's crash data.
type MobileApplicationCrashSummary struct {
SupportsCrashData bool `json:"supports_crash_data,omitempty"`
UnresolvedCrashCount int `json:"unresolved_crash_count,omitempty"`
CrashCount int `json:"crash_count,omitempty"`
CrashRate float64 `json:"crash_rate,omitempty"`
}
// MobileApplication describes a New Relic Application Host.
type MobileApplication struct {
ID int `json:"id,omitempty"`
Name string `json:"name,omitempty"`
HealthStatus string `json:"health_status,omitempty"`
Reporting bool `json:"reporting,omitempty"`
MobileSummary MobileApplicationSummary `json:"mobile_summary,omitempty"`
CrashSummary MobileApplicationCrashSummary `json:"crash_summary,omitempty"`
}
// GetMobileApplications returns a slice of New Relic Mobile Applications.
func (c *Client) GetMobileApplications() ([]MobileApplication, error) {
resp := &struct {
Applications []MobileApplication `json:"applications,omitempty"`
}{}
path := "mobile_applications.json"
err := c.doGet(path, nil, resp)
if err != nil {
return nil, err
}
return resp.Applications, nil
}
// GetMobileApplication returns a single Mobile Application with the id.
func (c *Client) GetMobileApplication(id int) (*MobileApplication, error) {
resp := &struct {
Application MobileApplication `json:"application,omitempty"`
}{}
path := "mobile_applications/" + strconv.Itoa(id) + ".json"
err := c.doGet(path, nil, resp)
if err != nil {
return nil, err
}
return &resp.Application, nil
}

View File

@@ -0,0 +1,78 @@
package newrelic
import (
"strconv"
)
// NotificationChannelLinks describes object links for notification channels.
type NotificationChannelLinks struct {
NotificationChannels []int `json:"notification_channels,omitempty"`
User int `json:"user,omitempty"`
}
// NotificationChannel describes a New Relic notification channel.
type NotificationChannel struct {
ID int `json:"id,omitempty"`
Type string `json:"type,omitempty"`
DowntimeOnly bool `json:"downtime_only,omitempty"`
URL string `json:"url,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Email string `json:"email,omitempty"`
Subdomain string `json:"subdomain,omitempty"`
Service string `json:"service,omitempty"`
MobileAlerts bool `json:"mobile_alerts,omitempty"`
EmailAlerts bool `json:"email_alerts,omitempty"`
Room string `json:"room,omitempty"`
Links NotificationChannelLinks `json:"links,omitempty"`
}
// NotificationChannelsFilter provides filters for
// NotificationChannelsOptions.
type NotificationChannelsFilter struct {
Type []string
IDs []int
}
// NotificationChannelsOptions is an optional means of filtering when calling
// GetNotificationChannels.
type NotificationChannelsOptions struct {
Filter NotificationChannelsFilter
Page int
}
func (o *NotificationChannelsOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"filter[type]": o.Filter.Type,
"filter[ids]": o.Filter.IDs,
"page": o.Page,
})
}
// GetNotificationChannel will return the NotificationChannel with particular ID.
func (c *Client) GetNotificationChannel(id int) (*NotificationChannel, error) {
resp := &struct {
NotificationChannel *NotificationChannel `json:"notification_channel,omitempty"`
}{}
err := c.doGet("notification_channels/"+strconv.Itoa(id)+".json", nil, resp)
if err != nil {
return nil, err
}
return resp.NotificationChannel, nil
}
// GetNotificationChannels will return a slice of NotificationChannel items,
// optionally filtering by NotificationChannelsOptions.
func (c *Client) GetNotificationChannels(options *NotificationChannelsOptions) ([]NotificationChannel, error) {
resp := &struct {
NotificationChannels []NotificationChannel `json:"notification_channels,omitempty"`
}{}
err := c.doGet("notification_channels.json", options, resp)
if err != nil {
return nil, err
}
return resp.NotificationChannels, nil
}

View File

@@ -0,0 +1,34 @@
package newrelic
import (
"fmt"
)
// GetServerMetrics will return a slice of Metric items for a particular
// Server ID, optionally filtering by MetricsOptions.
func (c *Client) GetServerMetrics(id int, options *MetricsOptions) ([]Metric, error) {
mc := NewMetricClient(c)
return mc.GetMetrics(
fmt.Sprintf(
"servers/%d/metrics.json",
id,
),
options,
)
}
// GetServerMetricData will return all metric data for a particular Server and
// slice of metric names, optionally filtered by MetricDataOptions.
func (c *Client) GetServerMetricData(id int, names []string, options *MetricDataOptions) (*MetricDataResponse, error) {
mc := NewMetricClient(c)
return mc.GetMetricData(
fmt.Sprintf(
"servers/%d/metrics/data.json",
id,
),
names,
options,
)
}

View File

@@ -0,0 +1,92 @@
package newrelic
import (
"strconv"
"time"
)
// ServersFilter is the filtering component of ServersOptions.
type ServersFilter struct {
Name string
Host string
IDs []int
Labels []string
Reported bool
}
// ServersOptions provides a filtering mechanism for GetServers.
type ServersOptions struct {
Filter ServersFilter
Page int
}
// ServerSummary describes the summary component of a Server.
type ServerSummary struct {
CPU float64 `json:"cpu,omitempty"`
CPUStolen float64 `json:"cpu_stolen,omitempty"`
DiskIO float64 `json:"disk_io,omitempty"`
Memory float64 `json:"memory,omitempty"`
MemoryUsed int64 `json:"memory_used,omitempty"`
MemoryTotal int64 `json:"memory_total,omitempty"`
FullestDisk float64 `json:"fullest_disk,omitempty"`
FullestDiskFree int64 `json:"fullest_disk_free,omitempty"`
}
// ServerLinks link Servers to the objects to which they pertain.
type ServerLinks struct {
AlertPolicy int `json:"alert_policy,omitempty"`
}
// Server represents a New Relic Server.
type Server struct {
ID int `json:"id,omitempty"`
AccountID int `json:"account_id,omitempty"`
Name string `json:"name,omitempty"`
Host string `json:"host,omitempty"`
HealthStatus string `json:"health_status,omitempty"`
Reporting bool `json:"reporting,omitempty"`
LastReportedAt time.Time `json:"last_reported_at,omitempty"`
Summary ServerSummary `json:"summary,omitempty"`
Links ServerLinks `json:"links,omitempty"`
}
// GetServers will return a slice of New Relic Servers, optionally filtered by
// ServerOptions.
func (c *Client) GetServers(opt *ServersOptions) ([]Server, error) {
resp := &struct {
Servers []Server `json:"servers,omitempty"`
}{}
path := "servers.json"
err := c.doGet(path, opt, resp)
if err != nil {
return nil, err
}
return resp.Servers, nil
}
// GetServer will return a single New Relic Server for the given id.
func (c *Client) GetServer(id int) (*Server, error) {
resp := &struct {
Server *Server `json:"server,omitempty"`
}{}
path := "servers/" + strconv.Itoa(id) + ".json"
err := c.doGet(path, nil, resp)
if err != nil {
return nil, err
}
return resp.Server, nil
}
func (o *ServersOptions) String() string {
if o == nil {
return ""
}
return encodeGetParams(map[string]interface{}{
"filter[name]": o.Filter.Name,
"filter[host]": o.Filter.Host,
"filter[ids]": o.Filter.IDs,
"filter[labels]": o.Filter.Labels,
"filter[reported]": o.Filter.Reported,
"page": o.Page,
})
}

View File

@@ -0,0 +1,49 @@
package newrelic
import (
"time"
)
// Usage describes usage over a single time period.
type Usage struct {
From time.Time `json"from,omitempty"`
To time.Time `json:"to,omitempty"`
Usage int `json:"usage,omitempty"`
}
// UsageData represents usage data for a product over a time frame, including
// a slice of Usages.
type UsageData struct {
Product string `json:"product,omitempty"`
From time.Time `json:"from,omitempty"`
To time.Time `json:"to,omitempty"`
Unit string `json:"unit,omitempty"`
Usages []Usage `json:"usages,omitempty"`
}
type usageParams struct {
Start time.Time
End time.Time
IncludeSubaccount bool
}
func (o *usageParams) String() string {
return encodeGetParams(map[string]interface{}{
"start_date": o.Start.Format("2006-01-02"),
"end_date": o.End.Format("2006-01-02"),
"include_subaccounts": o.IncludeSubaccount,
})
}
// GetUsages will return usage for a product in a given time frame.
func (c *Client) GetUsages(product string, start, end time.Time, includeSubaccounts bool) (*UsageData, error) {
resp := &struct {
UsageData *UsageData `json:"usage_data,omitempty"`
}{}
options := &usageParams{start, end, includeSubaccounts}
err := c.doGet("usages/"+product+".json", options, resp)
if err != nil {
return nil, err
}
return resp.UsageData, nil
}