Skip to content

Commit 1d8ba7b

Browse files
authored
Add support for shallow cloning azcore.Client instances (#21065)
* Add support for shallow cloning azcore.Client instances This allows for multiple clients to share the same underlying pipeline while having the correct client name string in traces. * improved field names
1 parent d8d2b43 commit 1d8ba7b

File tree

3 files changed

+73
-1
lines changed

3 files changed

+73
-1
lines changed

sdk/azcore/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Features Added
66

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

910
### Breaking Changes
1011

sdk/azcore/core.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ type ClientOptions = policy.ClientOptions
7373
type Client struct {
7474
pl runtime.Pipeline
7575
tr tracing.Tracer
76+
77+
// cached on the client to support shallow copying with new values
78+
tp tracing.Provider
79+
modVer string
80+
namespace string
7681
}
7782

7883
// NewClient creates a new Client instance with the provided values.
@@ -103,7 +108,14 @@ func NewClient(clientName, moduleVersion string, plOpts runtime.PipelineOptions,
103108
if tr.Enabled() && plOpts.TracingNamespace != "" {
104109
tr.SetAttributes(tracing.Attribute{Key: "az.namespace", Value: plOpts.TracingNamespace})
105110
}
106-
return &Client{pl: pl, tr: tr}, nil
111+
112+
return &Client{
113+
pl: pl,
114+
tr: tr,
115+
tp: options.TracingProvider,
116+
modVer: moduleVersion,
117+
namespace: plOpts.TracingNamespace,
118+
}, nil
107119
}
108120

109121
// Pipeline returns the pipeline for this client.
@@ -115,3 +127,14 @@ func (c *Client) Pipeline() runtime.Pipeline {
115127
func (c *Client) Tracer() tracing.Tracer {
116128
return c.tr
117129
}
130+
131+
// WithClientName returns a shallow copy of the Client with its tracing client name changed to clientName.
132+
// Note that the values for module name and version will be preserved from the source Client.
133+
// - clientName - the fully qualified name of the client ("package.Client"); this is used by the tracing provider when creating spans
134+
func (c *Client) WithClientName(clientName string) *Client {
135+
tr := c.tp.NewTracer(clientName, c.modVer)
136+
if tr.Enabled() && c.namespace != "" {
137+
tr.SetAttributes(tracing.Attribute{Key: "az.namespace", Value: c.namespace})
138+
}
139+
return &Client{pl: c.pl, tr: tr, tp: c.tp, modVer: c.modVer, namespace: c.namespace}
140+
}

sdk/azcore/core_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,51 @@ func TestNewClientTracingEnabled(t *testing.T) {
172172
require.NoError(t, err)
173173
require.EqualValues(t, "az.namespace:Widget.Factory", attrString)
174174
}
175+
176+
func TestClientWithClientName(t *testing.T) {
177+
srv, close := mock.NewServer()
178+
defer close()
179+
180+
var clientName string
181+
var modVersion string
182+
var attrString string
183+
client, err := NewClient("module/package.Client", "v1.0.0", runtime.PipelineOptions{TracingNamespace: "Widget.Factory"}, &policy.ClientOptions{
184+
TracingProvider: tracing.NewProvider(func(name, version string) tracing.Tracer {
185+
clientName = name
186+
modVersion = version
187+
return tracing.NewTracer(func(ctx context.Context, spanName string, options *tracing.SpanOptions) (context.Context, tracing.Span) {
188+
require.NotNil(t, options)
189+
for _, attr := range options.Attributes {
190+
if attr.Key == "az.namespace" {
191+
v, ok := attr.Value.(string)
192+
require.True(t, ok)
193+
attrString = attr.Key + ":" + v
194+
}
195+
}
196+
return ctx, tracing.Span{}
197+
}, nil)
198+
}, nil),
199+
Transport: srv,
200+
})
201+
require.NoError(t, err)
202+
require.NotNil(t, client)
203+
require.NotZero(t, client.Pipeline())
204+
require.NotZero(t, client.Tracer())
205+
require.EqualValues(t, "package.Client", clientName)
206+
require.EqualValues(t, "v1.0.0", modVersion)
207+
208+
const requestEndpoint = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/fakeResourceGroupo/providers/Microsoft.Storage/storageAccounts/fakeAccountName"
209+
req, err := exported.NewRequest(context.WithValue(context.Background(), shared.CtxWithTracingTracer{}, client.Tracer()), http.MethodGet, srv.URL()+requestEndpoint)
210+
require.NoError(t, err)
211+
srv.SetResponse()
212+
_, err = client.Pipeline().Do(req)
213+
require.NoError(t, err)
214+
require.EqualValues(t, "az.namespace:Widget.Factory", attrString)
215+
216+
newClient := client.WithClientName("other.Client")
217+
require.EqualValues(t, "other.Client", clientName)
218+
require.EqualValues(t, "v1.0.0", modVersion)
219+
_, err = newClient.Pipeline().Do(req)
220+
require.NoError(t, err)
221+
require.EqualValues(t, "az.namespace:Widget.Factory", attrString)
222+
}

0 commit comments

Comments
 (0)