10
10
import com .azure .core .exception .HttpResponseException ;
11
11
import com .azure .core .exception .ResourceModifiedException ;
12
12
import com .azure .core .exception .ResourceNotFoundException ;
13
+ import com .azure .core .http .HttpHeader ;
13
14
import com .azure .core .http .rest .RequestOptions ;
14
15
import com .azure .core .http .rest .Response ;
15
16
import com .azure .core .util .BinaryData ;
16
17
import com .azure .core .util .Context ;
18
+ import com .azure .core .util .logging .ClientLogger ;
19
+ import com .azure .monitor .ingestion .implementation .Batcher ;
20
+ import com .azure .monitor .ingestion .implementation .IngestionUsingDataCollectionRulesClient ;
21
+ import com .azure .monitor .ingestion .implementation .LogsIngestionRequest ;
22
+ import com .azure .monitor .ingestion .implementation .UploadLogsResponseHolder ;
23
+ import com .azure .monitor .ingestion .models .LogsUploadError ;
24
+ import com .azure .monitor .ingestion .models .LogsUploadException ;
17
25
import com .azure .monitor .ingestion .models .LogsUploadOptions ;
18
26
27
+ import java .util .List ;
28
+ import java .util .Objects ;
29
+ import java .util .concurrent .ExecutionException ;
30
+ import java .util .concurrent .ExecutorService ;
31
+ import java .util .function .Consumer ;
32
+ import java .util .stream .Collectors ;
33
+ import java .util .stream .Stream ;
34
+
35
+ import static com .azure .monitor .ingestion .implementation .Utils .CONTENT_ENCODING ;
36
+ import static com .azure .monitor .ingestion .implementation .Utils .GZIP ;
37
+ import static com .azure .monitor .ingestion .implementation .Utils .createThreadPool ;
38
+ import static com .azure .monitor .ingestion .implementation .Utils .getConcurrency ;
39
+ import static com .azure .monitor .ingestion .implementation .Utils .gzipRequest ;
40
+ import static com .azure .monitor .ingestion .implementation .Utils .registerShutdownHook ;
41
+
19
42
/**
20
43
* The synchronous client for uploading logs to Azure Monitor.
21
44
*
30
53
* <!-- end com.azure.monitor.ingestion.LogsIngestionClient.instantiation -->
31
54
*/
32
55
@ ServiceClient (builder = LogsIngestionClientBuilder .class )
33
- public final class LogsIngestionClient {
56
+ public final class LogsIngestionClient implements AutoCloseable {
57
+ private static final ClientLogger LOGGER = new ClientLogger (LogsIngestionClient .class );
58
+ private static final String HTTP_REST_PROXY_SYNC_PROXY_ENABLE = "com.azure.core.http.restproxy.syncproxy.enable" ;
59
+ private static final Context ENABLE_SYNC_CONTEXT = new Context (HTTP_REST_PROXY_SYNC_PROXY_ENABLE , true );
60
+ private final IngestionUsingDataCollectionRulesClient client ;
34
61
35
- private final LogsIngestionAsyncClient asyncClient ;
62
+ // dynamic thread pool that scales up and down on demand.
63
+ private final ExecutorService threadPool ;
64
+ private final Thread shutdownHook ;
36
65
37
- LogsIngestionClient (LogsIngestionAsyncClient asyncClient ) {
38
- this .asyncClient = asyncClient ;
66
+ LogsIngestionClient (IngestionUsingDataCollectionRulesClient client ) {
67
+ this .client = client ;
68
+ this .threadPool = createThreadPool ();
69
+ this .shutdownHook = registerShutdownHook (this .threadPool , 5 );
39
70
}
40
71
41
72
/**
@@ -61,7 +92,7 @@ public final class LogsIngestionClient {
61
92
*/
62
93
@ ServiceMethod (returns = ReturnType .SINGLE )
63
94
public void upload (String ruleId , String streamName , Iterable <Object > logs ) {
64
- asyncClient . upload (ruleId , streamName , logs ). block ( );
95
+ upload (ruleId , streamName , logs , null );
65
96
}
66
97
67
98
/**
@@ -90,7 +121,7 @@ public void upload(String ruleId, String streamName, Iterable<Object> logs) {
90
121
@ ServiceMethod (returns = ReturnType .SINGLE )
91
122
public void upload (String ruleId , String streamName ,
92
123
Iterable <Object > logs , LogsUploadOptions options ) {
93
- asyncClient . upload (ruleId , streamName , logs , options , Context .NONE ). block ( );
124
+ upload (ruleId , streamName , logs , options , Context .NONE );
94
125
}
95
126
96
127
/**
@@ -111,7 +142,64 @@ public void upload(String ruleId, String streamName,
111
142
@ ServiceMethod (returns = ReturnType .SINGLE )
112
143
public void upload (String ruleId , String streamName ,
113
144
Iterable <Object > logs , LogsUploadOptions options , Context context ) {
114
- asyncClient .upload (ruleId , streamName , logs , options , context ).block ();
145
+ Objects .requireNonNull (ruleId , "'ruleId' cannot be null." );
146
+ Objects .requireNonNull (streamName , "'streamName' cannot be null." );
147
+ Objects .requireNonNull (logs , "'logs' cannot be null." );
148
+
149
+ context = enableSync (context );
150
+
151
+ Consumer <LogsUploadError > uploadLogsErrorConsumer = options == null ? null : options .getLogsUploadErrorConsumer ();
152
+
153
+ RequestOptions requestOptions = new RequestOptions ();
154
+ requestOptions .addHeader (CONTENT_ENCODING , GZIP );
155
+ requestOptions .setContext (context );
156
+
157
+ Stream <UploadLogsResponseHolder > responses = new Batcher (options , logs )
158
+ .toStream ()
159
+ .map (r -> uploadToService (ruleId , streamName , requestOptions , r ));
160
+
161
+ responses = submit (responses , getConcurrency (options ))
162
+ .filter (response -> response .getException () != null );
163
+
164
+ if (uploadLogsErrorConsumer != null ) {
165
+ responses .forEach (response -> uploadLogsErrorConsumer .accept (new LogsUploadError (response .getException (), response .getRequest ().getLogs ())));
166
+ return ;
167
+ }
168
+
169
+ final int [] failedLogCount = new int [1 ];
170
+ List <HttpResponseException > exceptions = responses
171
+ .map (response -> {
172
+ failedLogCount [0 ] += response .getRequest ().getLogs ().size ();
173
+ return response .getException ();
174
+ })
175
+ .collect (Collectors .toList ());
176
+
177
+ if (exceptions .size () > 0 ) {
178
+ throw LOGGER .logExceptionAsError (new LogsUploadException (exceptions , failedLogCount [0 ]));
179
+ }
180
+ }
181
+
182
+ private Stream <UploadLogsResponseHolder > submit (Stream <UploadLogsResponseHolder > responseStream , int concurrency ) {
183
+ if (concurrency == 1 ) {
184
+ return responseStream ;
185
+ }
186
+
187
+ try {
188
+ return threadPool .submit (() -> responseStream ).get ();
189
+ } catch (InterruptedException | ExecutionException e ) {
190
+ throw LOGGER .logExceptionAsError (new RuntimeException (e ));
191
+ }
192
+ }
193
+
194
+ private UploadLogsResponseHolder uploadToService (String ruleId , String streamName , RequestOptions requestOptions , LogsIngestionRequest request ) {
195
+ HttpResponseException exception = null ;
196
+ try {
197
+ client .uploadWithResponse (ruleId , streamName , BinaryData .fromBytes (request .getRequestBody ()), requestOptions );
198
+ } catch (HttpResponseException ex ) {
199
+ exception = ex ;
200
+ }
201
+
202
+ return new UploadLogsResponseHolder (request , exception );
115
203
}
116
204
117
205
/**
@@ -147,6 +235,37 @@ public void upload(String ruleId, String streamName,
147
235
@ ServiceMethod (returns = ReturnType .SINGLE )
148
236
public Response <Void > uploadWithResponse (
149
237
String ruleId , String streamName , BinaryData logs , RequestOptions requestOptions ) {
150
- return asyncClient .uploadWithResponse (ruleId , streamName , logs , requestOptions ).block ();
238
+ Objects .requireNonNull (ruleId , "'ruleId' cannot be null." );
239
+ Objects .requireNonNull (streamName , "'streamName' cannot be null." );
240
+ Objects .requireNonNull (logs , "'logs' cannot be null." );
241
+
242
+ if (requestOptions == null ) {
243
+ requestOptions = new RequestOptions ();
244
+ }
245
+
246
+ requestOptions .setContext (enableSync (requestOptions .getContext ()));
247
+ requestOptions .addRequestCallback (request -> {
248
+ HttpHeader httpHeader = request .getHeaders ().get (CONTENT_ENCODING );
249
+ if (httpHeader == null ) {
250
+ BinaryData gzippedRequest = BinaryData .fromBytes (gzipRequest (logs .toBytes ()));
251
+ request .setBody (gzippedRequest );
252
+ request .setHeader (CONTENT_ENCODING , GZIP );
253
+ }
254
+ });
255
+ return client .uploadWithResponse (ruleId , streamName , logs , requestOptions );
256
+ }
257
+
258
+ private static Context enableSync (Context context ) {
259
+ if (context == null || context == Context .NONE ) {
260
+ return ENABLE_SYNC_CONTEXT ;
261
+ }
262
+
263
+ return context .addData (HTTP_REST_PROXY_SYNC_PROXY_ENABLE , true );
264
+ }
265
+
266
+ @ Override
267
+ public void close () {
268
+ threadPool .shutdown ();
269
+ Runtime .getRuntime ().removeShutdownHook (shutdownHook );
151
270
}
152
271
}
0 commit comments