Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
mv string
Comment thread
jhendrixMSFT marked this conversation as resolved.
Outdated
ns 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,
mv: moduleVersion,
ns: 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.mv)
if tr.Enabled() && c.ns != "" {
tr.SetAttributes(tracing.Attribute{Key: "az.namespace", Value: c.ns})
}
return &Client{pl: c.pl, tr: tr, tp: c.tp, mv: c.mv, ns: c.ns}
}
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)
}