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 support for shallow cloning azcore.Client instances #21065

Merged
merged 2 commits into from
Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdk/azcore/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Features Added

- `messaging/CloudEvent` allows you to serialize/deserialize CloudEvents, as described in the CloudEvents 1.0 specification: [link](https://github.com/cloudevents/spec)
* Added method `WithClientName()` to type `azcore.Client` to support shallow cloning of a client with a new name used for tracing.

### Breaking Changes

Expand Down
25 changes: 24 additions & 1 deletion sdk/azcore/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ type ClientOptions = policy.ClientOptions
type Client struct {
pl runtime.Pipeline
tr tracing.Tracer

// cached on the client to support shallow copying with new values
tp tracing.Provider
modVer string
namespace string
}

// NewClient creates a new Client instance with the provided values.
Expand Down Expand Up @@ -103,7 +108,14 @@ func NewClient(clientName, moduleVersion string, plOpts runtime.PipelineOptions,
if tr.Enabled() && plOpts.TracingNamespace != "" {
tr.SetAttributes(tracing.Attribute{Key: "az.namespace", Value: plOpts.TracingNamespace})
}
return &Client{pl: pl, tr: tr}, nil

return &Client{
pl: pl,
tr: tr,
tp: options.TracingProvider,
modVer: moduleVersion,
namespace: plOpts.TracingNamespace,
}, nil
}

// Pipeline returns the pipeline for this client.
Expand All @@ -115,3 +127,14 @@ func (c *Client) Pipeline() runtime.Pipeline {
func (c *Client) Tracer() tracing.Tracer {
return c.tr
}

// WithClientName returns a shallow copy of the Client with its tracing client name changed to clientName.
// Note that the values for module name and version will be preserved from the source Client.
// - clientName - the fully qualified name of the client ("package.Client"); this is used by the tracing provider when creating spans
func (c *Client) WithClientName(clientName string) *Client {
tr := c.tp.NewTracer(clientName, c.modVer)
if tr.Enabled() && c.namespace != "" {
tr.SetAttributes(tracing.Attribute{Key: "az.namespace", Value: c.namespace})
}
return &Client{pl: c.pl, tr: tr, tp: c.tp, modVer: c.modVer, namespace: c.namespace}
}
48 changes: 48 additions & 0 deletions sdk/azcore/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,51 @@ func TestNewClientTracingEnabled(t *testing.T) {
require.NoError(t, err)
require.EqualValues(t, "az.namespace:Widget.Factory", attrString)
}

func TestClientWithClientName(t *testing.T) {
srv, close := mock.NewServer()
defer close()

var clientName string
var modVersion string
var attrString string
client, err := NewClient("module/package.Client", "v1.0.0", runtime.PipelineOptions{TracingNamespace: "Widget.Factory"}, &policy.ClientOptions{
TracingProvider: tracing.NewProvider(func(name, version string) tracing.Tracer {
clientName = name
modVersion = version
return tracing.NewTracer(func(ctx context.Context, spanName string, options *tracing.SpanOptions) (context.Context, tracing.Span) {
require.NotNil(t, options)
for _, attr := range options.Attributes {
if attr.Key == "az.namespace" {
v, ok := attr.Value.(string)
require.True(t, ok)
attrString = attr.Key + ":" + v
}
}
return ctx, tracing.Span{}
}, nil)
}, nil),
Transport: srv,
})
require.NoError(t, err)
require.NotNil(t, client)
require.NotZero(t, client.Pipeline())
require.NotZero(t, client.Tracer())
require.EqualValues(t, "package.Client", clientName)
require.EqualValues(t, "v1.0.0", modVersion)

const requestEndpoint = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/fakeResourceGroupo/providers/Microsoft.Storage/storageAccounts/fakeAccountName"
req, err := exported.NewRequest(context.WithValue(context.Background(), shared.CtxWithTracingTracer{}, client.Tracer()), http.MethodGet, srv.URL()+requestEndpoint)
require.NoError(t, err)
srv.SetResponse()
_, err = client.Pipeline().Do(req)
require.NoError(t, err)
require.EqualValues(t, "az.namespace:Widget.Factory", attrString)

newClient := client.WithClientName("other.Client")
require.EqualValues(t, "other.Client", clientName)
require.EqualValues(t, "v1.0.0", modVersion)
_, err = newClient.Pipeline().Do(req)
require.NoError(t, err)
require.EqualValues(t, "az.namespace:Widget.Factory", attrString)
}