-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Send metrics to Azure * grant current user "Monitoring Metrics Publisher" on platform * add config to generate custom metrics endpoint * update readme * remove Float64() metric until it may be needed * add additional metrics
- Loading branch information
1 parent
f9f0a70
commit dcd5deb
Showing
15 changed files
with
325 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package metrics | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"strings" | ||
"time" | ||
|
||
"github.com/Azure/azure-sdk-for-go/sdk/azcore" | ||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" | ||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" | ||
"github.com/xenitab/azcagit/src/config" | ||
) | ||
|
||
type AzureMetrics struct { | ||
pl runtime.Pipeline | ||
customMetricsEndpoint string | ||
azureRegion string | ||
} | ||
|
||
var _ Metrics = (*AzureMetrics)(nil) | ||
|
||
func NewAzureMetrics(cfg config.Config, credential azcore.TokenCredential) *AzureMetrics { | ||
// The `//` in `https://monitoring.azure.com//.default` is intentional and the required audience is `https://monitoring.azure.com/`, | ||
// right now something happens inside of the `runtime` which makes the audience `https://monitoring.azure.com` when there's a single `/`. | ||
authPolicy := runtime.NewBearerTokenPolicy(credential, []string{"https://monitoring.azure.com//.default"}, nil) | ||
pl := runtime.NewPipeline("azcagit", "undefined", runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy}}, &policy.ClientOptions{}) | ||
return &AzureMetrics{ | ||
pl: pl, | ||
customMetricsEndpoint: generateCustomMetricsEndpoint(cfg), | ||
azureRegion: sanitizeAzureLocation(cfg.Location), | ||
} | ||
} | ||
|
||
func generateCustomMetricsEndpoint(cfg config.Config) string { | ||
azureRegion := sanitizeAzureLocation(cfg.Location) | ||
resourceId := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.App/containerApps/%s", cfg.SubscriptionID, cfg.OwnResourceGroupName, cfg.OwnContainerAppName) | ||
return fmt.Sprintf("https://%s.monitoring.azure.com/%s/metrics", azureRegion, resourceId) | ||
|
||
} | ||
|
||
func sanitizeAzureLocation(location string) string { | ||
locationWithoutSpaces := strings.ReplaceAll(location, " ", "") | ||
lowercaseLocation := strings.ToLower(locationWithoutSpaces) | ||
return lowercaseLocation | ||
} | ||
|
||
func (m *AzureMetrics) Int(ctx context.Context, metricName string, metric int) error { | ||
customMetrics := newCustomMetrics(m.azureRegion, metricName, float64(metric)) | ||
return m.create(ctx, customMetrics) | ||
} | ||
|
||
func (m *AzureMetrics) Duration(ctx context.Context, metricName string, metric time.Duration) error { | ||
customMetrics := newCustomMetrics(m.azureRegion, metricName, metric.Seconds()) | ||
return m.create(ctx, customMetrics) | ||
} | ||
|
||
func (m *AzureMetrics) Success(ctx context.Context, metricName string, metric bool) error { | ||
metricVal := float64(0) | ||
if metric { | ||
metricVal = 1 | ||
} | ||
customMetrics := newCustomMetrics(m.azureRegion, metricName, metricVal) | ||
return m.create(ctx, customMetrics) | ||
} | ||
|
||
func newCustomMetrics(region string, metricName string, metric float64) CustomMetrics { | ||
return CustomMetrics{ | ||
Time: time.Now(), | ||
Data: CustomMetricsData{ | ||
BaseData: CustomMetricsBaseData{ | ||
Metric: metricName, | ||
Namespace: "azcagit", | ||
DimNames: []string{ | ||
"region", | ||
}, | ||
Series: []CustomMetricsSeries{ | ||
{ | ||
DimValues: []string{ | ||
region, | ||
}, | ||
Min: metric, | ||
Max: metric, | ||
Sum: metric, | ||
Count: 1, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
type CustomMetricsSeries struct { | ||
DimValues []string `json:"dimValues,omitempty"` | ||
Min float64 `json:"min,omitempty"` | ||
Max float64 `json:"max,omitempty"` | ||
Sum float64 `json:"sum,omitempty"` | ||
Count int `json:"count,omitempty"` | ||
} | ||
|
||
type CustomMetricsBaseData struct { | ||
Metric string `json:"metric,omitempty"` | ||
Namespace string `json:"namespace,omitempty"` | ||
DimNames []string `json:"dimNames,omitempty"` | ||
Series []CustomMetricsSeries `json:"series,omitempty"` | ||
} | ||
|
||
type CustomMetricsData struct { | ||
BaseData CustomMetricsBaseData `json:"baseData,omitempty"` | ||
} | ||
|
||
type CustomMetrics struct { | ||
Time time.Time `json:"time,omitempty"` | ||
Data CustomMetricsData `json:"data,omitempty"` | ||
} | ||
|
||
func (client *AzureMetrics) create(ctx context.Context, body CustomMetrics) error { | ||
req, err := client.customCreateRequest(ctx, body) | ||
if err != nil { | ||
return err | ||
} | ||
resp, err := client.pl.Do(req) | ||
if err != nil { | ||
return err | ||
} | ||
if !runtime.HasStatusCode(resp, http.StatusOK) { | ||
return runtime.NewResponseError(resp) | ||
} | ||
return nil | ||
} | ||
|
||
func (client *AzureMetrics) customCreateRequest(ctx context.Context, body CustomMetrics) (*policy.Request, error) { | ||
req, err := runtime.NewRequest(ctx, http.MethodPost, client.customMetricsEndpoint) | ||
if err != nil { | ||
return nil, err | ||
} | ||
req.Raw().Header["Accept"] = []string{"application/json"} | ||
return req, runtime.MarshalAsJSON(req, body) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package metrics | ||
|
||
import ( | ||
"context" | ||
"time" | ||
) | ||
|
||
type InMemMetrics struct { | ||
intMetrics []int | ||
durationMetrics []time.Duration | ||
successMetrics []bool | ||
} | ||
|
||
func NewInMemMetrics() *InMemMetrics { | ||
return &InMemMetrics{} | ||
} | ||
|
||
var _ Metrics = (*InMemMetrics)(nil) | ||
|
||
func (m *InMemMetrics) Int(ctx context.Context, metricName string, metric int) error { | ||
m.intMetrics = append(m.intMetrics, metric) | ||
return nil | ||
} | ||
|
||
func (m *InMemMetrics) IntStats() []int { | ||
return m.intMetrics | ||
} | ||
|
||
func (m *InMemMetrics) Duration(ctx context.Context, metricName string, metric time.Duration) error { | ||
m.durationMetrics = append(m.durationMetrics, metric) | ||
return nil | ||
} | ||
|
||
func (m *InMemMetrics) DurationStats() []time.Duration { | ||
return m.durationMetrics | ||
} | ||
|
||
func (m *InMemMetrics) Success(ctx context.Context, metricName string, metric bool) error { | ||
m.successMetrics = append(m.successMetrics, metric) | ||
return nil | ||
} | ||
|
||
func (m *InMemMetrics) SuccessStats() []bool { | ||
return m.successMetrics | ||
} | ||
|
||
func (m *InMemMetrics) Reset() { | ||
m.intMetrics = []int{} | ||
m.durationMetrics = []time.Duration{} | ||
m.successMetrics = []bool{} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package metrics | ||
|
||
import ( | ||
"context" | ||
"time" | ||
) | ||
|
||
type Metrics interface { | ||
Int(ctx context.Context, metricName string, metric int) error | ||
Duration(ctx context.Context, metricName string, metric time.Duration) error | ||
Success(ctx context.Context, metricName string, metric bool) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.