-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
[extension/solarwindsapmsettingsextension] Added remaining implementation of solarwindsapmsettingsextension #33315
Changes from 4 commits
d53d9da
f4258b1
f24f425
f4c6d03
4674c76
d1cba82
a0688c5
07212ee
08dc77b
baa26f9
0084eac
465c376
0120d04
172e950
8f65ad1
85091f5
0ef422b
d75baae
d471abb
4c61613
ca529fb
005f428
ce61f50
25be1fd
7b92892
080daef
7119763
1b59c85
a2ee3fa
da99852
2a17e91
78f38c0
59b1911
5c78537
0b1330b
574d3f0
5bb4ddc
82ef634
3f31f51
cdeee9f
9475c30
398f3f4
096ba0d
45ce744
630f1ce
a55f64e
a47f1c1
33570e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Use this changelog template to create an entry for release notes. | ||
|
||
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' | ||
change_type: enhancement | ||
|
||
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) | ||
component: solarwindsapmsettingsextension | ||
|
||
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). | ||
note: Added logic for refresh function | ||
|
||
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. | ||
issues: [27668] | ||
|
||
# (Optional) One or more lines of additional information to render under the primary note. | ||
# These lines will be padded with 2 spaces and then inserted directly into the document. | ||
# Use pipe (|) for multiline entries. | ||
subtext: | ||
|
||
# If your change doesn't affect end users or the exported elements of any package, | ||
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. | ||
# Optional: The change log or logs in which this entry should be included. | ||
# e.g. '[user]' or '[user, api]' | ||
# Include 'user' if the change is relevant to end users. | ||
# Include 'api' if there is a change to a library API. | ||
# Default: '[user]' | ||
change_logs: [] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,11 @@ package solarwindsapmsettingsextension // import "github.com/open-telemetry/open | |
import ( | ||
"context" | ||
"crypto/tls" | ||
"encoding/binary" | ||
"encoding/json" | ||
"math" | ||
"os" | ||
"strconv" | ||
"time" | ||
|
||
"github.com/solarwindscloud/apm-proto/go/collectorpb" | ||
|
@@ -14,6 +19,12 @@ import ( | |
"go.uber.org/zap" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/credentials" | ||
"google.golang.org/protobuf/encoding/protojson" | ||
) | ||
|
||
const ( | ||
JSONOutputFile = "/tmp/solarwinds-apm-settings.json" | ||
GrpcContextDeadline = time.Duration(1) * time.Second | ||
jerrytfleung marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
|
||
type solarwindsapmSettingsExtension struct { | ||
|
@@ -76,6 +87,131 @@ func (extension *solarwindsapmSettingsExtension) Shutdown(_ context.Context) err | |
} | ||
|
||
func refresh(extension *solarwindsapmSettingsExtension) { | ||
// Concrete implementation will be available in later PR | ||
extension.logger.Info("refresh task") | ||
extension.logger.Info("Time to refresh from " + extension.config.Endpoint) | ||
if hostname, err := os.Hostname(); err != nil { | ||
extension.logger.Error("Unable to call os.Hostname() " + err.Error()) | ||
} else { | ||
ctx, cancel := context.WithTimeout(context.Background(), GrpcContextDeadline) | ||
defer cancel() | ||
|
||
request := &collectorpb.SettingsRequest{ | ||
ApiKey: extension.config.Key, | ||
Identity: &collectorpb.HostID{ | ||
Hostname: hostname, | ||
}, | ||
ClientVersion: "2", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In I wonder if this should be set as part of the package coming in or use the provided collector version? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
} | ||
if response, err := extension.client.GetSettings(ctx, request); err != nil { | ||
extension.logger.Error("Unable to getSettings from " + extension.config.Endpoint + " " + err.Error()) | ||
jerrytfleung marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. consider an early exit here to avoid this gigantic else clause There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. Done. |
||
switch result := response.GetResult(); result { | ||
case collectorpb.ResultCode_OK: | ||
if len(response.GetWarning()) > 0 { | ||
extension.logger.Warn(response.GetWarning()) | ||
} | ||
var settings []map[string]any | ||
for _, item := range response.GetSettings() { | ||
marshalOptions := protojson.MarshalOptions{ | ||
UseEnumNumbers: true, | ||
EmitUnpopulated: true, | ||
} | ||
if settingBytes, err := marshalOptions.Marshal(item); err != nil { | ||
extension.logger.Warn("Error to marshal setting JSON[] byte from response.GetSettings() " + err.Error()) | ||
} else { | ||
setting := make(map[string]any) | ||
if err := json.Unmarshal(settingBytes, &setting); err != nil { | ||
extension.logger.Warn("Error to unmarshal setting JSON object from setting JSON[]byte " + err.Error()) | ||
} else { | ||
if value, ok := setting["value"].(string); ok { | ||
if num, err := strconv.ParseInt(value, 10, 0); err != nil { | ||
extension.logger.Warn("Unable to parse value " + value + " as number " + err.Error()) | ||
} else { | ||
setting["value"] = num | ||
} | ||
} | ||
if timestamp, ok := setting["timestamp"].(string); ok { | ||
if num, err := strconv.ParseInt(timestamp, 10, 0); err != nil { | ||
extension.logger.Warn("Unable to parse timestamp " + timestamp + " as number " + err.Error()) | ||
} else { | ||
setting["timestamp"] = num | ||
} | ||
} | ||
if ttl, ok := setting["ttl"].(string); ok { | ||
if num, err := strconv.ParseInt(ttl, 10, 0); err != nil { | ||
extension.logger.Warn("Unable to parse ttl " + ttl + " as number " + err.Error()) | ||
} else { | ||
setting["ttl"] = num | ||
} | ||
} | ||
if _, ok := setting["flags"]; ok { | ||
setting["flags"] = string(item.Flags) | ||
} | ||
if arguments, ok := setting["arguments"].(map[string]any); ok { | ||
if value, ok := item.Arguments["BucketCapacity"]; ok { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you add code coverage for all this new code? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. Done |
||
arguments["BucketCapacity"] = math.Float64frombits(binary.LittleEndian.Uint64(value)) | ||
} | ||
if value, ok := item.Arguments["BucketRate"]; ok { | ||
arguments["BucketRate"] = math.Float64frombits(binary.LittleEndian.Uint64(value)) | ||
} | ||
if value, ok := item.Arguments["TriggerRelaxedBucketCapacity"]; ok { | ||
arguments["TriggerRelaxedBucketCapacity"] = math.Float64frombits(binary.LittleEndian.Uint64(value)) | ||
} | ||
if value, ok := item.Arguments["TriggerRelaxedBucketRate"]; ok { | ||
arguments["TriggerRelaxedBucketRate"] = math.Float64frombits(binary.LittleEndian.Uint64(value)) | ||
} | ||
if value, ok := item.Arguments["TriggerStrictBucketCapacity"]; ok { | ||
arguments["TriggerStrictBucketCapacity"] = math.Float64frombits(binary.LittleEndian.Uint64(value)) | ||
} | ||
if value, ok := item.Arguments["TriggerStrictBucketRate"]; ok { | ||
arguments["TriggerStrictBucketRate"] = math.Float64frombits(binary.LittleEndian.Uint64(value)) | ||
} | ||
if value, ok := item.Arguments["MetricsFlushInterval"]; ok { | ||
arguments["MetricsFlushInterval"] = int32(binary.LittleEndian.Uint32(value)) | ||
} | ||
if value, ok := item.Arguments["MaxTransactions"]; ok { | ||
arguments["MaxTransactions"] = int32(binary.LittleEndian.Uint32(value)) | ||
} | ||
if value, ok := item.Arguments["MaxCustomMetrics"]; ok { | ||
arguments["MaxCustomMetrics"] = int32(binary.LittleEndian.Uint32(value)) | ||
} | ||
if value, ok := item.Arguments["EventsFlushInterval"]; ok { | ||
arguments["EventsFlushInterval"] = int32(binary.LittleEndian.Uint32(value)) | ||
} | ||
if value, ok := item.Arguments["ProfilingInterval"]; ok { | ||
arguments["ProfilingInterval"] = int32(binary.LittleEndian.Uint32(value)) | ||
} | ||
// Remove SignatureKey from collector response | ||
delete(arguments, "SignatureKey") | ||
} | ||
settings = append(settings, setting) | ||
} | ||
} | ||
} | ||
if content, err := json.Marshal(settings); err != nil { | ||
extension.logger.Warn("Error to marshal setting JSON[] byte from settings " + err.Error()) | ||
} else { | ||
if err := os.WriteFile(JSONOutputFile, content, 0600); err != nil { | ||
extension.logger.Error("Unable to write " + JSONOutputFile + " " + err.Error()) | ||
} else { | ||
if len(response.GetWarning()) > 0 { | ||
extension.logger.Warn(JSONOutputFile + " is refreshed (soft disabled)") | ||
} else { | ||
extension.logger.Info(JSONOutputFile + " is refreshed") | ||
} | ||
extension.logger.Info(string(content)) | ||
} | ||
} | ||
case collectorpb.ResultCode_TRY_LATER: | ||
extension.logger.Warn("GetSettings returned TRY_LATER " + response.GetWarning()) | ||
case collectorpb.ResultCode_INVALID_API_KEY: | ||
extension.logger.Warn("GetSettings returned INVALID_API_KEY " + response.GetWarning()) | ||
case collectorpb.ResultCode_LIMIT_EXCEEDED: | ||
extension.logger.Warn("GetSettings returned LIMIT_EXCEEDED " + response.GetWarning()) | ||
case collectorpb.ResultCode_REDIRECT: | ||
extension.logger.Warn("GetSettings returned REDIRECT " + response.GetWarning()) | ||
default: | ||
extension.logger.Warn("Unknown ResultCode from GetSettings " + response.GetWarning()) | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do those need to be exported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. I fixed it.