Skip to content

Commit a85b474

Browse files
authored
Audit logging (#868)
1 parent 9135d84 commit a85b474

File tree

16 files changed

+302
-93
lines changed

16 files changed

+302
-93
lines changed

services-api/src/main/java/io/scalecube/services/ServiceCall.java

Lines changed: 95 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import io.scalecube.services.routing.Router;
1212
import io.scalecube.services.routing.Routers;
1313
import io.scalecube.services.transport.api.ClientTransport;
14+
import java.lang.System.Logger;
15+
import java.lang.System.Logger.Level;
1416
import java.lang.reflect.InvocationHandler;
1517
import java.lang.reflect.Method;
1618
import java.lang.reflect.Proxy;
@@ -34,6 +36,8 @@ public class ServiceCall implements AutoCloseable {
3436
private ServiceClientErrorMapper errorMapper = DefaultErrorMapper.INSTANCE;
3537
private Map<String, String> credentials = Collections.emptyMap();
3638
private String contentType = ServiceMessage.DEFAULT_DATA_FORMAT;
39+
private Logger logger;
40+
private Level level;
3741

3842
public ServiceCall() {}
3943

@@ -44,6 +48,8 @@ private ServiceCall(ServiceCall other) {
4448
this.errorMapper = other.errorMapper;
4549
this.contentType = other.contentType;
4650
this.credentials = Collections.unmodifiableMap(new HashMap<>(other.credentials));
51+
this.logger = other.logger;
52+
this.level = other.level;
4753
}
4854

4955
/**
@@ -130,6 +136,30 @@ public ServiceCall contentType(String contentType) {
130136
return target;
131137
}
132138

139+
/**
140+
* Setter for {@code logger}.
141+
*
142+
* @param name logger name.
143+
* @param level logger level.
144+
* @return new {@link ServiceCall} instance.
145+
*/
146+
public ServiceCall logger(String name, Level level) {
147+
ServiceCall target = new ServiceCall(this);
148+
target.logger = System.getLogger(name);
149+
target.level = level;
150+
return target;
151+
}
152+
153+
/**
154+
* Setter for {@code logger}.
155+
*
156+
* @param name logger name.
157+
* @return new {@link ServiceCall} instance.
158+
*/
159+
public ServiceCall logger(String name) {
160+
return logger(name, Level.DEBUG);
161+
}
162+
133163
/**
134164
* Issues fire-and-forget request.
135165
*
@@ -159,24 +189,41 @@ public Mono<ServiceMessage> requestOne(ServiceMessage request) {
159189
*/
160190
public Mono<ServiceMessage> requestOne(ServiceMessage request, Type responseType) {
161191
return Mono.defer(
162-
() -> {
163-
ServiceMethodInvoker methodInvoker;
164-
if (serviceRegistry != null
165-
&& (methodInvoker = serviceRegistry.getInvoker(request.qualifier())) != null) {
166-
// local service
167-
return methodInvoker.invokeOne(request).map(this::throwIfError);
168-
} else {
169-
// remote service
170-
Objects.requireNonNull(transport, "[requestOne] transport");
171-
return Mono.fromCallable(() -> serviceLookup(request))
172-
.flatMap(
173-
serviceReference ->
174-
transport
175-
.create(serviceReference)
176-
.requestResponse(request, responseType)
177-
.map(this::throwIfError));
178-
}
179-
});
192+
() -> {
193+
ServiceMethodInvoker methodInvoker;
194+
if (serviceRegistry != null
195+
&& (methodInvoker = serviceRegistry.getInvoker(request.qualifier())) != null) {
196+
// local service
197+
return methodInvoker.invokeOne(request).map(this::throwIfError);
198+
} else {
199+
// remote service
200+
Objects.requireNonNull(transport, "[requestOne] transport");
201+
return Mono.fromCallable(() -> serviceLookup(request))
202+
.flatMap(
203+
serviceReference ->
204+
transport
205+
.create(serviceReference)
206+
.requestResponse(request, responseType)
207+
.map(this::throwIfError));
208+
}
209+
})
210+
.doOnSuccess(
211+
response -> {
212+
if (logger != null && logger.isLoggable(level)) {
213+
logger.log(
214+
level,
215+
"[{0}] request: {1}, response: {2}",
216+
request.qualifier(),
217+
request,
218+
response);
219+
}
220+
})
221+
.doOnError(
222+
ex -> {
223+
if (logger != null) {
224+
logger.log(Level.ERROR, "[{0}] request: {1}", request.qualifier(), request, ex);
225+
}
226+
});
180227
}
181228

182229
/**
@@ -198,24 +245,36 @@ public Flux<ServiceMessage> requestMany(ServiceMessage request) {
198245
*/
199246
public Flux<ServiceMessage> requestMany(ServiceMessage request, Type responseType) {
200247
return Flux.defer(
201-
() -> {
202-
ServiceMethodInvoker methodInvoker;
203-
if (serviceRegistry != null
204-
&& (methodInvoker = serviceRegistry.getInvoker(request.qualifier())) != null) {
205-
// local service
206-
return methodInvoker.invokeMany(request).map(this::throwIfError);
207-
} else {
208-
// remote service
209-
Objects.requireNonNull(transport, "[requestMany] transport");
210-
return Mono.fromCallable(() -> serviceLookup(request))
211-
.flatMapMany(
212-
serviceReference ->
213-
transport
214-
.create(serviceReference)
215-
.requestStream(request, responseType)
216-
.map(this::throwIfError));
217-
}
218-
});
248+
() -> {
249+
ServiceMethodInvoker methodInvoker;
250+
if (serviceRegistry != null
251+
&& (methodInvoker = serviceRegistry.getInvoker(request.qualifier())) != null) {
252+
// local service
253+
return methodInvoker.invokeMany(request).map(this::throwIfError);
254+
} else {
255+
// remote service
256+
Objects.requireNonNull(transport, "[requestMany] transport");
257+
return Mono.fromCallable(() -> serviceLookup(request))
258+
.flatMapMany(
259+
serviceReference ->
260+
transport
261+
.create(serviceReference)
262+
.requestStream(request, responseType)
263+
.map(this::throwIfError));
264+
}
265+
})
266+
.doOnSubscribe(
267+
s -> {
268+
if (logger != null && logger.isLoggable(level)) {
269+
logger.log(level, "[{0}] request: {1}", request.qualifier(), request);
270+
}
271+
})
272+
.doOnError(
273+
ex -> {
274+
if (logger != null) {
275+
logger.log(Level.ERROR, "[{0}] request: {1}", request.qualifier(), request, ex);
276+
}
277+
});
219278
}
220279

221280
/**

services-api/src/main/java/io/scalecube/services/ServiceInfo.java

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import io.scalecube.services.auth.PrincipalMapper;
55
import io.scalecube.services.exceptions.ServiceProviderErrorMapper;
66
import io.scalecube.services.transport.api.ServiceMessageDataDecoder;
7+
import java.lang.System.Logger;
8+
import java.lang.System.Logger.Level;
79
import java.util.Collections;
810
import java.util.HashMap;
911
import java.util.Map;
@@ -18,6 +20,8 @@ public class ServiceInfo {
1820
private final ServiceMessageDataDecoder dataDecoder;
1921
private final Authenticator<Object> authenticator;
2022
private final PrincipalMapper<Object, Object> principalMapper;
23+
private final Logger logger;
24+
private final Level level;
2125

2226
private ServiceInfo(Builder builder) {
2327
this.serviceInstance = builder.serviceInstance;
@@ -26,6 +30,8 @@ private ServiceInfo(Builder builder) {
2630
this.dataDecoder = builder.dataDecoder;
2731
this.authenticator = builder.authenticator;
2832
this.principalMapper = builder.principalMapper;
33+
this.logger = builder.logger;
34+
this.level = builder.level;
2935
}
3036

3137
public static Builder from(ServiceInfo serviceInfo) {
@@ -60,15 +66,25 @@ public PrincipalMapper<Object, Object> principalMapper() {
6066
return principalMapper;
6167
}
6268

69+
public Logger logger() {
70+
return logger;
71+
}
72+
73+
public Level level() {
74+
return level;
75+
}
76+
6377
@Override
6478
public String toString() {
6579
return new StringJoiner(", ", ServiceInfo.class.getSimpleName() + "[", "]")
6680
.add("serviceInstance=" + serviceInstance)
67-
.add("tags(" + tags.size() + ")")
81+
.add("tags=" + tags)
6882
.add("errorMapper=" + errorMapper)
6983
.add("dataDecoder=" + dataDecoder)
7084
.add("authenticator=" + authenticator)
7185
.add("principalMapper=" + principalMapper)
86+
.add("logger=" + logger)
87+
.add("level=" + level)
7288
.toString();
7389
}
7490

@@ -80,6 +96,8 @@ public static class Builder {
8096
private ServiceMessageDataDecoder dataDecoder;
8197
private Authenticator<Object> authenticator;
8298
private PrincipalMapper<Object, Object> principalMapper;
99+
private Logger logger;
100+
private Level level;
83101

84102
private Builder(ServiceInfo serviceInfo) {
85103
this.serviceInstance = serviceInfo.serviceInstance;
@@ -88,6 +106,8 @@ private Builder(ServiceInfo serviceInfo) {
88106
this.dataDecoder = serviceInfo.dataDecoder;
89107
this.authenticator = serviceInfo.authenticator;
90108
this.principalMapper = serviceInfo.principalMapper;
109+
this.logger = serviceInfo.logger;
110+
this.level = serviceInfo.level;
91111
}
92112

93113
private Builder(Object serviceInstance) {
@@ -98,8 +118,8 @@ private Builder(Object serviceInstance) {
98118
* Setter for {@code tags}. Merges this {@code tags} with {@code Microservices.tags}. If keys
99119
* are clashing this {@code tags} shall override {@code Microservices.tags}.
100120
*
101-
* @param key tag key; not null
102-
* @param value tag value; not null
121+
* @param key tag key
122+
* @param value tag value
103123
* @return this builder
104124
*/
105125
public Builder tag(String key, String value) {
@@ -112,18 +132,41 @@ public Builder tag(String key, String value) {
112132
/**
113133
* Setter for {@code errorMapper}. Overrides default {@code Microservices.errorMapper}.
114134
*
115-
* @param errorMapper error mapper; not null
135+
* @param errorMapper error mapper
116136
* @return this buidler
117137
*/
118138
public Builder errorMapper(ServiceProviderErrorMapper errorMapper) {
119139
this.errorMapper = Objects.requireNonNull(errorMapper, "errorMapper");
120140
return this;
121141
}
122142

143+
/**
144+
* Setter for {@code logger}. Overrides default {@code Microservices.logger}.
145+
*
146+
* @param name logger name (optional)
147+
* @param level logger level (optional)
148+
* @return this buidler
149+
*/
150+
public Builder logger(String name, Level level) {
151+
this.logger = name != null ? System.getLogger(name) : null;
152+
this.level = level;
153+
return this;
154+
}
155+
156+
/**
157+
* Setter for {@code logger}. Overrides default {@code Microservices.logger}.
158+
*
159+
* @param name logger name (optional)
160+
* @return this buidler
161+
*/
162+
public Builder logger(String name) {
163+
return logger(name, Level.DEBUG);
164+
}
165+
123166
/**
124167
* Setter for {@code dataDecoder}. Overrides default {@code Microservices.dataDecoder}.
125168
*
126-
* @param dataDecoder data decoder; not null
169+
* @param dataDecoder data decoder
127170
* @return this builder
128171
*/
129172
public Builder dataDecoder(ServiceMessageDataDecoder dataDecoder) {
@@ -134,7 +177,7 @@ public Builder dataDecoder(ServiceMessageDataDecoder dataDecoder) {
134177
/**
135178
* Setter for {@code authenticator}. Overrides default {@code Microservices.authenticator}.
136179
*
137-
* @param authenticator authenticator; optional
180+
* @param authenticator authenticator (optional)
138181
* @param <T> type of auth data returned by authenticator
139182
* @return this builder
140183
*/
@@ -147,7 +190,7 @@ public <T> Builder authenticator(Authenticator<? extends T> authenticator) {
147190
/**
148191
* Setter for {@code principalMapper}. Overrides default {@code Microservices.principalMapper}.
149192
*
150-
* @param principalMapper principalMapper; optional
193+
* @param principalMapper principalMapper (optional)
151194
* @param <T> auth data type
152195
* @param <R> principal type
153196
* @return this builder
@@ -160,28 +203,35 @@ public <T, R> Builder principalMapper(PrincipalMapper<? super T, ? extends R> pr
160203

161204
Builder errorMapperIfAbsent(ServiceProviderErrorMapper errorMapper) {
162205
if (this.errorMapper == null) {
163-
this.errorMapper = errorMapper;
206+
return errorMapper(errorMapper);
164207
}
165208
return this;
166209
}
167210

168211
Builder dataDecoderIfAbsent(ServiceMessageDataDecoder dataDecoder) {
169212
if (this.dataDecoder == null) {
170-
this.dataDecoder = dataDecoder;
213+
return dataDecoder(dataDecoder);
171214
}
172215
return this;
173216
}
174217

175218
Builder authenticatorIfAbsent(Authenticator<Object> authenticator) {
176219
if (this.authenticator == null) {
177-
this.authenticator = authenticator;
220+
return authenticator(authenticator);
178221
}
179222
return this;
180223
}
181224

182225
Builder principalMapperIfAbsent(PrincipalMapper<Object, Object> principalMapper) {
183226
if (this.principalMapper == null) {
184-
this.principalMapper = principalMapper;
227+
return principalMapper(principalMapper);
228+
}
229+
return this;
230+
}
231+
232+
Builder loggerIfAbsent(String name, Level level) {
233+
if (this.logger == null) {
234+
return logger(name, level);
185235
}
186236
return this;
187237
}

services-api/src/main/java/io/scalecube/services/api/ServiceMessage.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,9 @@ public int errorType() {
189189

190190
@Override
191191
public String toString() {
192-
return new StringJoiner(", ", ServiceMessage.class.getSimpleName() + "[", "]")
192+
return new StringJoiner(", ", "ServiceMessage" + "[", "]")
193193
.add("headers(" + headers.size() + ")")
194-
.add("data=" + (data != null ? data.getClass().getName() : null))
194+
.add("data=" + data)
195195
.toString();
196196
}
197197

@@ -205,7 +205,7 @@ private Builder() {}
205205
/**
206206
* Setter for {@code data}.
207207
*
208-
* @param data data; optional
208+
* @param data data (optional)
209209
* @return this builder
210210
*/
211211
public Builder data(Object data) {

0 commit comments

Comments
 (0)