Skip to content

Commit 278b2c8

Browse files
committed
Merge pull request #874 from elasticsearch/feature/nodes-hot-threads
Add support for NodesHotThreads
2 parents 50d57aa + 6351b57 commit 278b2c8

File tree

11 files changed

+245
-17
lines changed

11 files changed

+245
-17
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+

2+
using Elasticsearch.Net;
3+
using Elasticsearch.Net.Serialization;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
9+
namespace Nest
10+
{
11+
internal static class NodesHotThreadsPathInfo
12+
{
13+
public static void Update(IConnectionSettingsValues settings, ElasticsearchPathInfo<NodesHotThreadsRequestParameters> pathInfo, INodesHotThreadsRequest request)
14+
{
15+
pathInfo.HttpMethod = PathInfoHttpMethod.GET;
16+
}
17+
}
18+
19+
public interface INodesHotThreadsRequest
20+
: INodeIdOptionalPath<NodesHotThreadsRequestParameters>
21+
{
22+
}
23+
24+
public partial class NodesHotThreadsRequest
25+
: NodeIdOptionalPathBase<NodesHotThreadsRequestParameters>, INodesHotThreadsRequest
26+
{
27+
protected override void UpdatePathInfo(IConnectionSettingsValues settings, ElasticsearchPathInfo<NodesHotThreadsRequestParameters> pathInfo)
28+
{
29+
NodesHotThreadsPathInfo.Update(settings, pathInfo, this);
30+
}
31+
}
32+
33+
public partial class NodesHotThreadsDescriptor
34+
: NodeIdOptionalPathBase<NodesHotThreadsRequestParameters>, INodesHotThreadsRequest
35+
{
36+
private INodesHotThreadsRequest Self { get { return this; } }
37+
38+
protected override void UpdatePathInfo(IConnectionSettingsValues settings, ElasticsearchPathInfo<NodesHotThreadsRequestParameters> pathInfo)
39+
{
40+
NodesHotThreadsPathInfo.Update(settings, pathInfo, this.Self);
41+
}
42+
}
43+
}

src/Nest/DSL/_Descriptors.generated.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4405,7 +4405,7 @@ public MultiTermVectorsDescriptor<T> Parent(string parent)
44054405
///http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.x/cluster-nodes-hot-threads.html
44064406
///</pre>
44074407
///</summary>
4408-
public partial class NodesHotThreadsDescriptor : BaseRequest<NodesHotThreadsRequestParameters>
4408+
public partial class NodesHotThreadsDescriptor
44094409
{
44104410

44114411

@@ -4441,12 +4441,6 @@ public NodesHotThreadsDescriptor ThreadType(ThreadType thread_type)
44414441
return this;
44424442
}
44434443

4444-
4445-
protected override void UpdatePathInfo(IConnectionSettingsValues settings, ElasticsearchPathInfo<NodesHotThreadsRequestParameters> pathInfo)
4446-
{
4447-
throw new NotImplementedException();
4448-
}
4449-
44504444

44514445
}
44524446

src/Nest/DSL/_Requests.generated.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3975,7 +3975,7 @@ public string Parent
39753975
///http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.x/cluster-nodes-hot-threads.html
39763976
///</pre>
39773977
///</summary>
3978-
public partial class NodesHotThreadsRequest : BasePathRequest<NodesHotThreadsRequestParameters>
3978+
public partial class NodesHotThreadsRequest
39793979
{
39803980

39813981
///<summary>The interval for the second sampling of threads</summary>
@@ -4009,12 +4009,6 @@ public ThreadType ThreadType
40094009
set { this.Request.RequestParameters.AddQueryString("type", value); }
40104010
}
40114011

4012-
4013-
protected override void UpdatePathInfo(IConnectionSettingsValues settings, ElasticsearchPathInfo<NodesHotThreadsRequestParameters> pathInfo)
4014-
{
4015-
throw new NotImplementedException();
4016-
}
4017-
40184012
}
40194013

40204014

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Nest.Resolvers.Converters;
2+
using Newtonsoft.Json;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
8+
namespace Nest
9+
{
10+
public class HotThreadInformation
11+
{
12+
public HotThreadInformation()
13+
{
14+
this.Threads = new List<string>();
15+
}
16+
17+
public string Node { get; set; }
18+
public List<string> Threads { get; set; }
19+
}
20+
21+
public interface INodesHotThreadsResponse : IResponse
22+
{
23+
List<HotThreadInformation> HotThreads { get; }
24+
}
25+
26+
public class NodesHotThreadsResponse : BaseResponse, INodesHotThreadsResponse
27+
{
28+
public NodesHotThreadsResponse()
29+
{
30+
this.HotThreads = new List<HotThreadInformation>();
31+
}
32+
33+
public List<HotThreadInformation> HotThreads { get; set; }
34+
}
35+
}

src/Nest/ElasticClient-Nodes.cs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22
using System.Collections.Generic;
33
using System.Threading.Tasks;
44
using Elasticsearch.Net;
5+
using System.IO;
6+
using System.Linq;
57

68
namespace Nest
79
{
10+
using NodesHotThreadConverter = Func<IElasticsearchResponse, Stream, NodesHotThreadsResponse>;
11+
using System.Text.RegularExpressions;
12+
using System.Text;
13+
814
public partial class ElasticClient
915
{
1016
/// <inheritdoc />
@@ -85,5 +91,86 @@ public Task<INodeStatsResponse> NodesStatsAsync(INodesStatsRequest nodesStatsReq
8591
(p, d) => this.RawDispatch.NodesStatsDispatchAsync<NodeStatsResponse>(p)
8692
);
8793
}
94+
95+
/// <inheritdoc />
96+
public INodesHotThreadsResponse NodesHotThreads(Func<NodesHotThreadsDescriptor, NodesHotThreadsDescriptor> selector = null)
97+
{
98+
selector = selector ?? (s => s);
99+
return this.Dispatch<NodesHotThreadsDescriptor, NodesHotThreadsRequestParameters, NodesHotThreadsResponse>(
100+
selector,
101+
(p, d) => this.RawDispatch.NodesHotThreadsDispatch<NodesHotThreadsResponse>(
102+
p.DeserializationState(new NodesHotThreadConverter(DeserializeNodesHotThreadResponse)))
103+
);
104+
}
105+
106+
/// <inheritdoc />
107+
public INodesHotThreadsResponse NodesHotThreads(INodesHotThreadsRequest nodesHotThreadsRequest)
108+
{
109+
return this.Dispatch<INodesHotThreadsRequest, NodesHotThreadsRequestParameters, NodesHotThreadsResponse>(
110+
nodesHotThreadsRequest,
111+
(p, d) => this.RawDispatch.NodesHotThreadsDispatch<NodesHotThreadsResponse>(
112+
p.DeserializationState(new NodesHotThreadConverter(DeserializeNodesHotThreadResponse)))
113+
);
114+
}
115+
116+
/// <inheritdoc />
117+
public Task<INodesHotThreadsResponse> NodesHotThreadsAsync(Func<NodesHotThreadsDescriptor, NodesHotThreadsDescriptor> selector = null)
118+
{
119+
selector = selector ?? (s => s);
120+
return this.DispatchAsync<NodesHotThreadsDescriptor, NodesHotThreadsRequestParameters, NodesHotThreadsResponse, INodesHotThreadsResponse>(
121+
selector,
122+
(p, d) => this.RawDispatch.NodesHotThreadsDispatchAsync<NodesHotThreadsResponse>(
123+
p.DeserializationState(new NodesHotThreadConverter(DeserializeNodesHotThreadResponse)))
124+
);
125+
}
126+
127+
/// <inheritdoc />
128+
public Task<INodesHotThreadsResponse> NodesHotThreadsAsync(INodesHotThreadsRequest nodesHotThreadsRequest)
129+
{
130+
return this.DispatchAsync<INodesHotThreadsRequest, NodesHotThreadsRequestParameters, NodesHotThreadsResponse, INodesHotThreadsResponse>(
131+
nodesHotThreadsRequest,
132+
(p, d) => this.RawDispatch.NodesHotThreadsDispatchAsync<NodesHotThreadsResponse>(
133+
p.DeserializationState(new NodesHotThreadConverter(DeserializeNodesHotThreadResponse)))
134+
);
135+
}
136+
137+
/// <summary>
138+
/// Because the nodes.hot_threads endpoint returns plain text instead of JSON, we have to
139+
/// manually parse the response text into a typed response object.
140+
/// </summary>
141+
private NodesHotThreadsResponse DeserializeNodesHotThreadResponse(IElasticsearchResponse response, Stream stream)
142+
{
143+
var typedResponse = new NodesHotThreadsResponse();
144+
var plainTextResponse = Encoding.UTF8.GetString(response.ResponseRaw);
145+
146+
// If the response doesn't start with :::, which is the pattern that delimits
147+
// each node section in the response, then the response format isn't recognized.
148+
// Just return an empty response object. This is especially useful when unit
149+
// testing against an in-memory connection where you won't get a real response.
150+
if (!plainTextResponse.StartsWith(":::"))
151+
return typedResponse;
152+
153+
var sections = plainTextResponse.Split(new string[] { ":::" }, StringSplitOptions.RemoveEmptyEntries);
154+
155+
foreach(var section in sections)
156+
{
157+
var sectionLines = section.Split(new string[] { "\n \n" }, StringSplitOptions.None);
158+
159+
if (sectionLines.Length > 0)
160+
{
161+
var hotThreadInfo = new HotThreadInformation
162+
{
163+
// First line contains the node name between [ ]
164+
Node = sectionLines.First().Split('[')[1].TrimEnd(']'),
165+
// The rest of the lines are hot threads
166+
Threads = sectionLines.Skip(1).Take(sectionLines.Length - 1).ToList()
167+
};
168+
169+
typedResponse.HotThreads.Add(hotThreadInfo);
170+
}
171+
}
172+
173+
return typedResponse;
174+
}
88175
}
89176
}

src/Nest/ElasticClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4-
using System.Linq;
4+
using System.Linq;
55
using System.Threading.Tasks;
66
using Elasticsearch.Net;
77
using Elasticsearch.Net.Connection;

src/Nest/IElasticClient.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,23 @@ Task<IIndicesResponse> DeleteMappingAsync<T>(Func<DeleteMappingDescriptor<T>, De
612612

613613
/// <inheritdoc />
614614
Task<INodeStatsResponse> NodesStatsAsync(INodesStatsRequest nodesStatsRequest);
615-
615+
616+
/// <summary>
617+
/// An API allowing to get the current hot threads on each node in the cluster.
618+
/// </summary>
619+
/// <param name="selector"></param>
620+
/// <returns>An optional descriptor to further describe the nodes hot threads operation</returns>
621+
INodesHotThreadsResponse NodesHotThreads(Func<NodesHotThreadsDescriptor, NodesHotThreadsDescriptor> selector = null);
622+
623+
/// <inheritdoc />
624+
INodesHotThreadsResponse NodesHotThreads(INodesHotThreadsRequest nodesHotThreadsRequest);
625+
626+
/// <inheritdoc />
627+
Task<INodesHotThreadsResponse> NodesHotThreadsAsync(Func<NodesHotThreadsDescriptor, NodesHotThreadsDescriptor> selector = null);
628+
629+
/// <inheritdoc />
630+
Task<INodesHotThreadsResponse> NodesHotThreadsAsync(INodesHotThreadsRequest nodesHotThreadsRequest);
631+
616632
/// <summary>
617633
/// Used to check if the index (indices) exists or not.
618634
/// <para> </para>http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-exists.html

src/Nest/Nest.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@
167167
<Compile Include="Domain\Responses\ExplainResponse.cs" />
168168
<Compile Include="Domain\Responses\GetFieldMappingResponse.cs" />
169169
<Compile Include="Domain\Responses\MultiPercolateResponse.cs" />
170+
<Compile Include="Domain\Responses\NodesHotThreadsResponse.cs" />
170171
<Compile Include="DSL\Filter\GeoShapeCircleFilterDescriptor.cs" />
171172
<Compile Include="DSL\Filter\GeoShapeMultiLineStringFilterDescriptor.cs" />
172173
<Compile Include="DSL\Filter\GeoShapeMultiPointFilterDescriptor.cs" />
@@ -179,6 +180,7 @@
179180
<Compile Include="DSL\GetFieldMappingDescriptor.cs" />
180181
<Compile Include="DSL\MultiPercolate\IPercolateOperation.cs" />
181182
<Compile Include="DSL\MultiPercolateDescriptor.cs" />
183+
<Compile Include="DSL\NodesHotThreadsDescriptor.cs" />
182184
<Compile Include="DSL\Paths\IndexOptionalNamePathDescriptor.cs" />
183185
<Compile Include="DSL\Paths\IndicesOptionalTypesNamePathDecriptor.cs" />
184186
<Compile Include="DSL\Query\SubDescriptors\MoreLikeThisQueryDocumentsDescriptor.cs" />

src/Tests/Nest.Tests.Integration/Cluster/NodeTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Linq;
22
using Elasticsearch.Net;
3+
using FluentAssertions;
34
using NUnit.Framework;
45

56
namespace Nest.Tests.Integration.Cluster
@@ -50,5 +51,22 @@ public void NodeStats()
5051
Assert.IsNotNull(node.Transport);
5152
Assert.IsNotNull(node.HTTP);
5253
}
54+
55+
[Test]
56+
public void NodesHotThreads()
57+
{
58+
var r = this.Client.NodesHotThreads(n => n
59+
.Interval("20s")
60+
.Snapshots(5)
61+
.Threads(5)
62+
.ThreadType(ThreadType.Cpu)
63+
);
64+
65+
r.IsValid.Should().BeTrue();
66+
r.HotThreads.Count.Should().BeGreaterOrEqualTo(1);
67+
var hotThreadInfo = r.HotThreads.First();
68+
hotThreadInfo.Node.Should().NotBeNullOrEmpty();
69+
hotThreadInfo.Threads.Count.ShouldBeEquivalentTo(5);
70+
}
5371
}
5472
}

src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@
184184
<None Include="Core\Map\Properties\MultiFieldPropertyWithJustNamePath.json">
185185
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
186186
</None>
187-
<Compile Include="Core\Map\GetFieldMappingRequestTests.cs" />
188187
<Compile Include="Core\MultiPercolate\MultiPercolateTests.cs" />
189188
<Compile Include="Core\Map\Transform\MappingTansformTests.cs" />
190189
<Compile Include="Core\Scroll\ScrollRequestTests.cs" />
@@ -235,6 +234,7 @@
235234
<Compile Include="ObjectInitializer\Aliases\GetAliasRequestTests.cs" />
236235
<Compile Include="ObjectInitializer\Aliases\GetAliasesRequestTests.cs" />
237236
<Compile Include="ObjectInitializer\Aliases\AliasRequestTests.cs" />
237+
<Compile Include="ObjectInitializer\Nodes\NodesHotThreadsRequestTests.cs" />
238238
<Compile Include="ObjectInitializer\Status\StatusRequestTests.cs" />
239239
<Compile Include="ObjectInitializer\IndicesStats\IndicesStatsRequestTests.cs" />
240240
<Compile Include="ObjectInitializer\ClusterState\ClusterStateRequestTests.cs" />

0 commit comments

Comments
 (0)