Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audit logging #868

Merged
merged 4 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 95 additions & 36 deletions services-api/src/main/java/io/scalecube/services/ServiceCall.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import io.scalecube.services.routing.Router;
import io.scalecube.services.routing.Routers;
import io.scalecube.services.transport.api.ClientTransport;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
Expand All @@ -34,6 +36,8 @@ public class ServiceCall implements AutoCloseable {
private ServiceClientErrorMapper errorMapper = DefaultErrorMapper.INSTANCE;
private Map<String, String> credentials = Collections.emptyMap();
private String contentType = ServiceMessage.DEFAULT_DATA_FORMAT;
private Logger logger;
private Level level;

public ServiceCall() {}

Expand All @@ -44,6 +48,8 @@ private ServiceCall(ServiceCall other) {
this.errorMapper = other.errorMapper;
this.contentType = other.contentType;
this.credentials = Collections.unmodifiableMap(new HashMap<>(other.credentials));
this.logger = other.logger;
this.level = other.level;
}

/**
Expand Down Expand Up @@ -130,6 +136,30 @@ public ServiceCall contentType(String contentType) {
return target;
}

/**
* Setter for {@code logger}.
*
* @param name logger name.
* @param level logger level.
* @return new {@link ServiceCall} instance.
*/
public ServiceCall logger(String name, Level level) {
ServiceCall target = new ServiceCall(this);
target.logger = System.getLogger(name);
target.level = level;
return target;
}

/**
* Setter for {@code logger}.
*
* @param name logger name.
* @return new {@link ServiceCall} instance.
*/
public ServiceCall logger(String name) {
return logger(name, Level.DEBUG);
}

/**
* Issues fire-and-forget request.
*
Expand Down Expand Up @@ -159,24 +189,41 @@ public Mono<ServiceMessage> requestOne(ServiceMessage request) {
*/
public Mono<ServiceMessage> requestOne(ServiceMessage request, Type responseType) {
return Mono.defer(
() -> {
ServiceMethodInvoker methodInvoker;
if (serviceRegistry != null
&& (methodInvoker = serviceRegistry.getInvoker(request.qualifier())) != null) {
// local service
return methodInvoker.invokeOne(request).map(this::throwIfError);
} else {
// remote service
Objects.requireNonNull(transport, "[requestOne] transport");
return Mono.fromCallable(() -> serviceLookup(request))
.flatMap(
serviceReference ->
transport
.create(serviceReference)
.requestResponse(request, responseType)
.map(this::throwIfError));
}
});
() -> {
ServiceMethodInvoker methodInvoker;
if (serviceRegistry != null
&& (methodInvoker = serviceRegistry.getInvoker(request.qualifier())) != null) {
// local service
return methodInvoker.invokeOne(request).map(this::throwIfError);
} else {
// remote service
Objects.requireNonNull(transport, "[requestOne] transport");
return Mono.fromCallable(() -> serviceLookup(request))
.flatMap(
serviceReference ->
transport
.create(serviceReference)
.requestResponse(request, responseType)
.map(this::throwIfError));
}
})
.doOnSuccess(
response -> {
if (logger != null && logger.isLoggable(level)) {
logger.log(
level,
"[{0}] request: {1}, response: {2}",
request.qualifier(),
request,
response);
}
})
.doOnError(
ex -> {
if (logger != null) {
logger.log(Level.ERROR, "[{0}] request: {1}", request.qualifier(), request, ex);
}
});
}

/**
Expand All @@ -198,24 +245,36 @@ public Flux<ServiceMessage> requestMany(ServiceMessage request) {
*/
public Flux<ServiceMessage> requestMany(ServiceMessage request, Type responseType) {
return Flux.defer(
() -> {
ServiceMethodInvoker methodInvoker;
if (serviceRegistry != null
&& (methodInvoker = serviceRegistry.getInvoker(request.qualifier())) != null) {
// local service
return methodInvoker.invokeMany(request).map(this::throwIfError);
} else {
// remote service
Objects.requireNonNull(transport, "[requestMany] transport");
return Mono.fromCallable(() -> serviceLookup(request))
.flatMapMany(
serviceReference ->
transport
.create(serviceReference)
.requestStream(request, responseType)
.map(this::throwIfError));
}
});
() -> {
ServiceMethodInvoker methodInvoker;
if (serviceRegistry != null
&& (methodInvoker = serviceRegistry.getInvoker(request.qualifier())) != null) {
// local service
return methodInvoker.invokeMany(request).map(this::throwIfError);
} else {
// remote service
Objects.requireNonNull(transport, "[requestMany] transport");
return Mono.fromCallable(() -> serviceLookup(request))
.flatMapMany(
serviceReference ->
transport
.create(serviceReference)
.requestStream(request, responseType)
.map(this::throwIfError));
}
})
.doOnSubscribe(
s -> {
if (logger != null && logger.isLoggable(level)) {
logger.log(level, "[{0}] request: {1}", request.qualifier(), request);
}
})
.doOnError(
ex -> {
if (logger != null) {
logger.log(Level.ERROR, "[{0}] request: {1}", request.qualifier(), request, ex);
}
});
}

/**
Expand Down
72 changes: 61 additions & 11 deletions services-api/src/main/java/io/scalecube/services/ServiceInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import io.scalecube.services.auth.PrincipalMapper;
import io.scalecube.services.exceptions.ServiceProviderErrorMapper;
import io.scalecube.services.transport.api.ServiceMessageDataDecoder;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -18,6 +20,8 @@ public class ServiceInfo {
private final ServiceMessageDataDecoder dataDecoder;
private final Authenticator<Object> authenticator;
private final PrincipalMapper<Object, Object> principalMapper;
private final Logger logger;
private final Level level;

private ServiceInfo(Builder builder) {
this.serviceInstance = builder.serviceInstance;
Expand All @@ -26,6 +30,8 @@ private ServiceInfo(Builder builder) {
this.dataDecoder = builder.dataDecoder;
this.authenticator = builder.authenticator;
this.principalMapper = builder.principalMapper;
this.logger = builder.logger;
this.level = builder.level;
}

public static Builder from(ServiceInfo serviceInfo) {
Expand Down Expand Up @@ -60,15 +66,25 @@ public PrincipalMapper<Object, Object> principalMapper() {
return principalMapper;
}

public Logger logger() {
return logger;
}

public Level level() {
return level;
}

@Override
public String toString() {
return new StringJoiner(", ", ServiceInfo.class.getSimpleName() + "[", "]")
.add("serviceInstance=" + serviceInstance)
.add("tags(" + tags.size() + ")")
.add("tags=" + tags)
.add("errorMapper=" + errorMapper)
.add("dataDecoder=" + dataDecoder)
.add("authenticator=" + authenticator)
.add("principalMapper=" + principalMapper)
.add("logger=" + logger)
.add("level=" + level)
.toString();
}

Expand All @@ -80,6 +96,8 @@ public static class Builder {
private ServiceMessageDataDecoder dataDecoder;
private Authenticator<Object> authenticator;
private PrincipalMapper<Object, Object> principalMapper;
private Logger logger;
private Level level;

private Builder(ServiceInfo serviceInfo) {
this.serviceInstance = serviceInfo.serviceInstance;
Expand All @@ -88,6 +106,8 @@ private Builder(ServiceInfo serviceInfo) {
this.dataDecoder = serviceInfo.dataDecoder;
this.authenticator = serviceInfo.authenticator;
this.principalMapper = serviceInfo.principalMapper;
this.logger = serviceInfo.logger;
this.level = serviceInfo.level;
}

private Builder(Object serviceInstance) {
Expand All @@ -98,8 +118,8 @@ private Builder(Object serviceInstance) {
* Setter for {@code tags}. Merges this {@code tags} with {@code Microservices.tags}. If keys
* are clashing this {@code tags} shall override {@code Microservices.tags}.
*
* @param key tag key; not null
* @param value tag value; not null
* @param key tag key
* @param value tag value
* @return this builder
*/
public Builder tag(String key, String value) {
Expand All @@ -112,18 +132,41 @@ public Builder tag(String key, String value) {
/**
* Setter for {@code errorMapper}. Overrides default {@code Microservices.errorMapper}.
*
* @param errorMapper error mapper; not null
* @param errorMapper error mapper
* @return this buidler
*/
public Builder errorMapper(ServiceProviderErrorMapper errorMapper) {
this.errorMapper = Objects.requireNonNull(errorMapper, "errorMapper");
return this;
}

/**
* Setter for {@code logger}. Overrides default {@code Microservices.logger}.
*
* @param name logger name (optional)
* @param level logger level (optional)
* @return this buidler
*/
public Builder logger(String name, Level level) {
this.logger = name != null ? System.getLogger(name) : null;
this.level = level;
return this;
}

/**
* Setter for {@code logger}. Overrides default {@code Microservices.logger}.
*
* @param name logger name (optional)
* @return this buidler
*/
public Builder logger(String name) {
return logger(name, Level.DEBUG);
}

/**
* Setter for {@code dataDecoder}. Overrides default {@code Microservices.dataDecoder}.
*
* @param dataDecoder data decoder; not null
* @param dataDecoder data decoder
* @return this builder
*/
public Builder dataDecoder(ServiceMessageDataDecoder dataDecoder) {
Expand All @@ -134,7 +177,7 @@ public Builder dataDecoder(ServiceMessageDataDecoder dataDecoder) {
/**
* Setter for {@code authenticator}. Overrides default {@code Microservices.authenticator}.
*
* @param authenticator authenticator; optional
* @param authenticator authenticator (optional)
* @param <T> type of auth data returned by authenticator
* @return this builder
*/
Expand All @@ -147,7 +190,7 @@ public <T> Builder authenticator(Authenticator<? extends T> authenticator) {
/**
* Setter for {@code principalMapper}. Overrides default {@code Microservices.principalMapper}.
*
* @param principalMapper principalMapper; optional
* @param principalMapper principalMapper (optional)
* @param <T> auth data type
* @param <R> principal type
* @return this builder
Expand All @@ -160,28 +203,35 @@ public <T, R> Builder principalMapper(PrincipalMapper<? super T, ? extends R> pr

Builder errorMapperIfAbsent(ServiceProviderErrorMapper errorMapper) {
if (this.errorMapper == null) {
this.errorMapper = errorMapper;
return errorMapper(errorMapper);
}
return this;
}

Builder dataDecoderIfAbsent(ServiceMessageDataDecoder dataDecoder) {
if (this.dataDecoder == null) {
this.dataDecoder = dataDecoder;
return dataDecoder(dataDecoder);
}
return this;
}

Builder authenticatorIfAbsent(Authenticator<Object> authenticator) {
if (this.authenticator == null) {
this.authenticator = authenticator;
return authenticator(authenticator);
}
return this;
}

Builder principalMapperIfAbsent(PrincipalMapper<Object, Object> principalMapper) {
if (this.principalMapper == null) {
this.principalMapper = principalMapper;
return principalMapper(principalMapper);
}
return this;
}

Builder loggerIfAbsent(String name, Level level) {
if (this.logger == null) {
return logger(name, level);
}
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,9 @@ public int errorType() {

@Override
public String toString() {
return new StringJoiner(", ", ServiceMessage.class.getSimpleName() + "[", "]")
return new StringJoiner(", ", "ServiceMessage" + "[", "]")
.add("headers(" + headers.size() + ")")
.add("data=" + (data != null ? data.getClass().getName() : null))
.add("data=" + data)
.toString();
}

Expand All @@ -205,7 +205,7 @@ private Builder() {}
/**
* Setter for {@code data}.
*
* @param data data; optional
* @param data data (optional)
* @return this builder
*/
public Builder data(Object data) {
Expand Down
Loading
Loading