Skip to content

Commit 8b49015

Browse files
committed
Include Diagnostic Source in troubleshooting
1 parent c4af296 commit 8b49015

File tree

5 files changed

+83
-85
lines changed

5 files changed

+83
-85
lines changed

docs/breaking-changes.asciidoc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ please modify the original csharp file found at the link and submit the PR with
1010

1111
[partintro]
1212
--
13-
There are a number of breaking changes when going from 5.x to 6.x
13+
There are a number of breaking changes when going from 6.x to 7.x
1414

1515
* <<elasticsearch-net-breaking-changes, Elasticsearch.Net breaking changes>>
1616
1717
* <<nest-breaking-changes, NEST breaking changes>>
1818
1919
--
2020

21-
include::6.0-breaking-changes/elasticsearch-net-breaking-changes.asciidoc[]
21+
include::7.0-breaking-changes/elasticsearch-net-breaking-changes.asciidoc[]
2222

23-
include::6.0-breaking-changes/nest-breaking-changes.asciidoc[]
23+
include::7.0-breaking-changes/nest-breaking-changes.asciidoc[]
2424

docs/client-concepts/troubleshooting/diagnostic-source.asciidoc

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,27 @@ please modify the original csharp file found at the link and submit the PR with
1515
[[diagnostic-source]]
1616
=== Diagnostic Source
1717

18-
Elasticsearch.Net and by proxy NEST ship with support for DiagnosticSource and Activity out of the box.
18+
Elasticsearch.Net and NEST support capturing diagnostics information using `DiagnosticSource` and `Activity` from the
19+
`System.Diagnostics` namespace.
1920

20-
To aid with their discover the topics you can subscribe on and the event names they emit are exposed as
21-
strongly typed strings under `Elasticsearch.Net.Diagnostics.DiagnosticSources`
21+
To aid with the discoverability of the topics you can subscribe to and the event names they emit,
22+
both topics and event names are exposed as strongly typed strings under `Elasticsearch.Net.Diagnostics.DiagnosticSources`
2223

2324
Subscribing to DiagnosticSources means implementing `IObserver<DiagnosticListener>`
24-
or use `.Subscribe(observer, filter)` to opt in to the correct topic.
25+
or using `.Subscribe(observer, filter)` to opt in to the correct topic.
2526

26-
Here we choose the more verbose `IObserver<>` implementation.
27+
Here we choose the more verbose `IObserver<>` implementation
2728

2829
[source,csharp]
2930
----
30-
private class ListenerObserver : IObserver<DiagnosticListener>, IDisposable
31+
public class ListenerObserver : IObserver<DiagnosticListener>, IDisposable
3132
{
3233
private long _messagesWrittenToConsole = 0;
3334
public long MessagesWrittenToConsole => _messagesWrittenToConsole;
3435
3536
public Exception SeenException { get; private set; }
36-
public void OnError(Exception error) => SeenException = error;
3737
38+
public void OnError(Exception error) => SeenException = error;
3839
public bool Completed { get; private set; }
3940
public void OnCompleted() => Completed = true;
4041
@@ -46,21 +47,9 @@ private class ListenerObserver : IObserver<DiagnosticListener>, IDisposable
4647
4748
private List<IDisposable> Disposables { get; } = new List<IDisposable>();
4849
49-
/**
50-
* By inspecting the name we selectively subscribe only to topics `Elasticsearch.Net` emits.
51-
*
52-
* Thanks to `DiagnosticSources` you do not have to guess the topics we emit under.
53-
*
54-
* `DiagnosticListener.Subscribe` expects an `IObserver<KeyValuePair<string, object>>` which is useful to create
55-
* a decoupled messaging contract but as a subscriber you would like to know what `object` is.
56-
*
57-
* Therefor each topic we ship with has a dedicated `Observer` implementation that takes an `onNext` lambda
58-
* which is typed to the context object we actually emit.
59-
*
60-
*/
6150
public void OnNext(DiagnosticListener value)
6251
{
63-
void TrySubscribe(string sourceName, Func<IObserver<KeyValuePair<string, object>>> listener)
52+
void TrySubscribe(string sourceName, Func<IObserver<KeyValuePair<string, object>>> listener) <1>
6453
{
6554
if (value.Name != sourceName) return;
6655
@@ -73,11 +62,7 @@ private class ListenerObserver : IObserver<DiagnosticListener>, IDisposable
7362
7463
TrySubscribe(DiagnosticSources.Serializer.SourceName,
7564
() => new SerializerDiagnosticObserver(v => WriteToConsole(v.Key, v.Value)));
76-
/**
77-
* RequestPipeline emits a different context object for the start of the `Activity` then it does
78-
* for the end of the `Activity` therefor `RequestPipelineDiagnosticObserver` accepts two `onNext` lambda's.
79-
* One for the `.Start` events and one for the `.Stop` events.
80-
*/
65+
8166
TrySubscribe(DiagnosticSources.RequestPipeline.SourceName,
8267
() => new RequestPipelineDiagnosticObserver(
8368
v => WriteToConsole(v.Key, v.Value),
@@ -97,38 +82,50 @@ private class ListenerObserver : IObserver<DiagnosticListener>, IDisposable
9782
}
9883
}
9984
----
85+
<1> By inspecting the name, we can selectively subscribe only to the topics `Elasticsearch.Net` emit
86+
87+
Thanks to `DiagnosticSources`, you do not have to guess the topics emitted.
88+
89+
The `DiagnosticListener.Subscribe` method expects an `IObserver<KeyValuePair<string, object>>`
90+
which is a rather generic message contract. As a subscriber, it's useful to know what `object` is in each case.
91+
To help with this, each topic within the client has a dedicated `Observer` implementation that
92+
takes an `onNext` delegate typed to the context object actually emitted.
10093

101-
Here we hook into all diagnostic sources and use `ListenerObserver` to only listen to the ones
102-
from `Elasticsearch.Net`
94+
The RequestPipeline diagnostic source emits a different context objects the start and end of the `Activity`
95+
For this reason, `RequestPipelineDiagnosticObserver` accepts two `onNext` delegates,
96+
one for the `.Start` events and one for the `.Stop` events.
97+
98+
[[subscribing-to-topics]]
99+
==== Subscribing to topics
100+
101+
As a concrete example of subscribing to topics, let's hook into all diagnostic sources and use
102+
`ListenerObserver` to only listen to the ones from `Elasticsearch.Net`
103103

104104
[source,csharp]
105105
----
106106
using(var listenerObserver = new ListenerObserver())
107107
using (var subscription = DiagnosticListener.AllListeners.Subscribe(listenerObserver))
108108
{
109-
110-
/**
111-
* We'll use a Sniffing connection pool here since it sniffs on startup and pings before
112-
* first usage, so our diagnostics are involved enough to showcase most topics.
113-
*/
114-
var pool = new SniffingConnectionPool(new []{ TestConnectionSettings.CreateUri() });
109+
var pool = new SniffingConnectionPool(new []{ TestConnectionSettings.CreateUri() }); <1>
115110
var connectionSettings = new ConnectionSettings(pool)
116111
.DefaultMappingFor<Project>(i => i
117112
.IndexName("project")
118113
);
119114
120115
var client = new ElasticClient(connectionSettings);
121116
122-
/**
123-
* After issuing the following request
124-
*/
125-
var response = client.Search<Project>(s => s
117+
var response = client.Search<Project>(s => s <2>
126118
.MatchAll()
127119
);
128120
129-
listenerObserver.SeenException.Should().BeNull();
121+
listenerObserver.SeenException.Should().BeNull(); <3>
130122
listenerObserver.Completed.Should().BeFalse();
131123
listenerObserver.MessagesWrittenToConsole.Should().BeGreaterThan(0);
132124
}
133125
----
126+
<1> use a sniffing connection pool that sniffs on startup and pings before first usage, so our diagnostics will emit most topics.
127+
128+
<2> make a search API call
129+
130+
<3> verify that the listener is picking up events
134131

docs/troubleshooting.asciidoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,18 @@ There are a couple of popular ways of capturing this information
3232

3333
* <<logging-with-fiddler, Using Fiddler>>
3434

35+
More detailed diagnostic information can be captured with
36+
37+
* <<diagnostic-source, Diagnostic Source>>
38+
3539
In addition to logging requests and responses, Elasticsearch 5.0+ also
3640
<<deprecation-logging, sends back warning headers>> in the response,
3741
to notify you if you are using a feature that is marked as deprecated.
3842

3943
include::client-concepts/troubleshooting/logging-with-on-request-completed.asciidoc[]
4044

45+
include::client-concepts/troubleshooting/diagnostic-source.asciidoc[]
46+
4147
include::client-concepts/troubleshooting/logging-with-fiddler.asciidoc[]
4248

4349
include::client-concepts/troubleshooting/deprecation-logging.asciidoc[]

src/Tests/Tests/ClientConcepts/Troubleshooting/DiagnosticSource.doc.cs

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,36 +20,36 @@
2020
namespace Tests.ClientConcepts.Troubleshooting
2121
{
2222
/**
23+
* [[diagnostic-source]]
2324
* === Diagnostic Source
2425
*
25-
* Elasticsearch.Net and by proxy NEST ship with support for DiagnosticSource and Activity out of the box.
26-
*
27-
* To aid with their discover the topics you can subscribe on and the event names they emit are exposed as
28-
* strongly typed strings under `Elasticsearch.Net.Diagnostics.DiagnosticSources`
26+
* Elasticsearch.Net and NEST support capturing diagnostics information using `DiagnosticSource` and `Activity` from the
27+
* `System.Diagnostics` namespace.
2928
*
29+
* To aid with the discoverability of the topics you can subscribe to and the event names they emit,
30+
* both topics and event names are exposed as strongly typed strings under `Elasticsearch.Net.Diagnostics.DiagnosticSources`
3031
*/
3132
public class DiagnosticSourceUsageDocumentation : IClusterFixture<ReadOnlyCluster>
3233
{
3334
private readonly ReadOnlyCluster _cluster;
3435

36+
// hide
3537
public DiagnosticSourceUsageDocumentation(ReadOnlyCluster cluster) => _cluster = cluster;
3638

37-
3839
/**
3940
* Subscribing to DiagnosticSources means implementing `IObserver<DiagnosticListener>`
40-
* or use `.Subscribe(observer, filter)` to opt in to the correct topic.
41-
*
42-
* Here we choose the more verbose `IObserver<>` implementation.
41+
* or using `.Subscribe(observer, filter)` to opt in to the correct topic.
4342
*
43+
* Here we choose the more verbose `IObserver<>` implementation
4444
*/
45-
private class ListenerObserver : IObserver<DiagnosticListener>, IDisposable
45+
public class ListenerObserver : IObserver<DiagnosticListener>, IDisposable
4646
{
4747
private long _messagesWrittenToConsole = 0;
4848
public long MessagesWrittenToConsole => _messagesWrittenToConsole;
4949

5050
public Exception SeenException { get; private set; }
51-
public void OnError(Exception error) => SeenException = error;
5251

52+
public void OnError(Exception error) => SeenException = error;
5353
public bool Completed { get; private set; }
5454
public void OnCompleted() => Completed = true;
5555

@@ -61,21 +61,9 @@ private void WriteToConsole<T>(string eventName, T data)
6161

6262
private List<IDisposable> Disposables { get; } = new List<IDisposable>();
6363

64-
/**
65-
* By inspecting the name we selectively subscribe only to topics `Elasticsearch.Net` emits.
66-
*
67-
* Thanks to `DiagnosticSources` you do not have to guess the topics we emit under.
68-
*
69-
* `DiagnosticListener.Subscribe` expects an `IObserver<KeyValuePair<string, object>>` which is useful to create
70-
* a decoupled messaging contract but as a subscriber you would like to know what `object` is.
71-
*
72-
* Therefor each topic we ship with has a dedicated `Observer` implementation that takes an `onNext` lambda
73-
* which is typed to the context object we actually emit.
74-
*
75-
*/
7664
public void OnNext(DiagnosticListener value)
7765
{
78-
void TrySubscribe(string sourceName, Func<IObserver<KeyValuePair<string, object>>> listener)
66+
void TrySubscribe(string sourceName, Func<IObserver<KeyValuePair<string, object>>> listener) // <1> By inspecting the name, we can selectively subscribe only to the topics `Elasticsearch.Net` emit
7967
{
8068
if (value.Name != sourceName) return;
8169

@@ -88,11 +76,7 @@ void TrySubscribe(string sourceName, Func<IObserver<KeyValuePair<string, object>
8876

8977
TrySubscribe(DiagnosticSources.Serializer.SourceName,
9078
() => new SerializerDiagnosticObserver(v => WriteToConsole(v.Key, v.Value)));
91-
/**
92-
* RequestPipeline emits a different context object for the start of the `Activity` then it does
93-
* for the end of the `Activity` therefor `RequestPipelineDiagnosticObserver` accepts two `onNext` lambda's.
94-
* One for the `.Start` events and one for the `.Stop` events.
95-
*/
79+
9680
TrySubscribe(DiagnosticSources.RequestPipeline.SourceName,
9781
() => new RequestPipelineDiagnosticObserver(
9882
v => WriteToConsole(v.Key, v.Value),
@@ -111,37 +95,43 @@ public void Dispose()
11195
foreach(var d in Disposables) d.Dispose();
11296
}
11397
}
114-
98+
/**
99+
* Thanks to `DiagnosticSources`, you do not have to guess the topics emitted.
100+
*
101+
* The `DiagnosticListener.Subscribe` method expects an `IObserver<KeyValuePair<string, object>>`
102+
* which is a rather generic message contract. As a subscriber, it's useful to know what `object` is in each case.
103+
* To help with this, each topic within the client has a dedicated `Observer` implementation that
104+
* takes an `onNext` delegate typed to the context object actually emitted.
105+
*
106+
* The RequestPipeline diagnostic source emits a different context objects the start and end of the `Activity`
107+
* For this reason, `RequestPipelineDiagnosticObserver` accepts two `onNext` delegates,
108+
* one for the `.Start` events and one for the `.Stop` events.
109+
*
110+
* [[subscribing-to-topics]]
111+
* ==== Subscribing to topics
112+
*
113+
* As a concrete example of subscribing to topics, let's hook into all diagnostic sources and use
114+
* `ListenerObserver` to only listen to the ones from `Elasticsearch.Net`
115+
*/
115116
[I] public void SubscribeToTopics()
116117
{
117-
/**
118-
* Here we hook into all diagnostic sources and use `ListenerObserver` to only listen to the ones
119-
* from `Elasticsearch.Net`
120-
*/
118+
121119
using(var listenerObserver = new ListenerObserver())
122120
using (var subscription = DiagnosticListener.AllListeners.Subscribe(listenerObserver))
123121
{
124-
125-
/**
126-
* We'll use a Sniffing connection pool here since it sniffs on startup and pings before
127-
* first usage, so our diagnostics are involved enough to showcase most topics.
128-
*/
129-
var pool = new SniffingConnectionPool(new []{ TestConnectionSettings.CreateUri() });
122+
var pool = new SniffingConnectionPool(new []{ TestConnectionSettings.CreateUri() }); // <1> use a sniffing connection pool that sniffs on startup and pings before first usage, so our diagnostics will emit most topics.
130123
var connectionSettings = new ConnectionSettings(pool)
131124
.DefaultMappingFor<Project>(i => i
132125
.IndexName("project")
133126
);
134127

135128
var client = new ElasticClient(connectionSettings);
136129

137-
/**
138-
* After issuing the following request
139-
*/
140-
var response = client.Search<Project>(s => s
130+
var response = client.Search<Project>(s => s // <2> make a search API call
141131
.MatchAll()
142132
);
143133

144-
listenerObserver.SeenException.Should().BeNull();
134+
listenerObserver.SeenException.Should().BeNull(); // <3> verify that the listener is picking up events
145135
listenerObserver.Completed.Should().BeFalse();
146136
listenerObserver.MessagesWrittenToConsole.Should().BeGreaterThan(0);
147137
}

src/Tests/Tests/troubleshooting.asciidoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,16 @@ There are a couple of popular ways of capturing this information
2222
- <<logging-with-on-request-completed, Using `OnRequestCompleted`>>
2323
- <<logging-with-fiddler, Using Fiddler, a web debugging proxy>>
2424

25+
More detailed diagnostic information can be captured with
26+
27+
- <<diagnostic-source, Diagnostic Source>>
28+
2529
In addition to logging requests and responses, Elasticsearch 5.0+ also
2630
<<deprecation-logging, sends back warning headers>> in the response,
2731
to notify you if you are using a feature that is marked as deprecated.
2832

2933
include::client-concepts/troubleshooting/logging-with-on-request-completed.asciidoc[]
34+
include::client-concepts/troubleshooting/diagnostic-source.asciidoc[]
3035
include::client-concepts/troubleshooting/logging-with-fiddler.asciidoc[]
3136
include::client-concepts/troubleshooting/deprecation-logging.asciidoc[]
3237

0 commit comments

Comments
 (0)