I want to send a message from Android okhttp3 websocket client, not just echoing the messages coming from the server. here is my websocket class:
// Websocket
public final class EchoWebSocketListener extends WebSocketListener {
private static final int NORMAL_CLOSURE_STATUS = 1000;
#Override
public void onOpen(WebSocket webSocket, Response response) {
webSocket.send(message);
}
#Override
public void onMessage(WebSocket webSocket, String text) {
printer("text");
}
#Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(NORMAL_CLOSURE_STATUS, null);
}
#Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
}
public void send(WebSocket webSocket) {
webSocket.send(finalMessage);
}
}
And here is how I call it from the onCreate method:
client= new OkHttpClient();
Request request = new Request.Builder().url(Url).build();
EchoWebSocketListener listener = new EchoWebSocketListener();
webso = myClient.newWebSocket(request, listener);
client.dispatcher().executorService().shutdown();
I tried to make an object to the class and call a function I named it 'send':
EchoWebSocketListener object = new EchoWebSocketListener ()
object.send(webso)
But that's not working?
recommend you this way RxWebSocket
Related
For a simple gRPC service defined by proto file:
service HelloService {
rpc sayHello() returns (stream string)
}
How can i wait on the client side to first wait for the headers to arrive before i start to process the response from server? I tried using ClientInterceptor and override the onHeaders() method but it gets called after the call to sayHello() is completed already. How can i validate for a specific header inside the sayHello client and proceed with the call based on the validity of the header?
public class SomeHeaderInterceptor implements ClientInterceptor {
private static final String FULL_METHOD_NAME = "sayHello";
public static CallOptions.Key<String> someHeader = CallOptions.Key.of("some_header_active", "false");
#Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions callOptions, Channel channel) {
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(channel.newCall(methodDescriptor, callOptions)) {
#Override
public void start(Listener<RespT> responseListener, Metadata headers) {
super.start(new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(responseListener) {
#Override
public void onHeaders(Metadata headers) {
Metadata.Key<String> SAYHELLO_ACTIVE_HEADER = Metadata.Key.of("some_header_active",
Metadata.ASCII_STRING_MARSHALLER);
if (methodDescriptor.getFullMethodName().equals(FULL_METHOD_NAME)) {
if (!headers.containsKey(SAYHELLO_ACTIVE_HEADER)) {
LOGGER.logError("some_header activation missing from header: " + headers);
} else {
callOptions.withOption(someHeader, "true");
Context.current().withValue(Context.key("test"), "testvalue");
}
}
super.onHeaders(headers);
}
}, headers);
}
};
}
And the code for sayHello is as follows:
public Iterator<String> sayHello() {
Iterator<String> stream = blockingStub.sayHello();
// wait for the sayhello active header
boolean isActive = Boolean.parseBoolean(blockingStub.getCallOptions().getOption(SomeHeaderInterceptor. someHeader));
System.out.println("the some_header header value is: " + isActive);
System.out.println("the context key : " + Context.key("test").get(Context.current()));
return stream;
}
In the sayHello() code above, it doesn't wait for the headers to arrive and context to be set in the onHeaders(). how can i do that? I only want to return the stream back to the client caller after i validate the presence of the some_header in the stream sent by the server.
The headers are sent by the server before the first message, so the easy way would be to call stream.hasNext(), which will block waiting on a message. In many RPCs the first message comes pretty soon after the response headers, so this would work reasonably well.
As an aside, I noticed you experimenting with CallOptions and Context:
callOptions.withOption(someHeader, "true");
Context.current().withValue(Context.key("test"), "testvalue");
Neither of those lines really does anything because both objects are immutable. The with* calls create a new instance, so you have to use the return value for the line to do anything. Also, CallOptions and Context predominantly pass information in the opposite direction, like from the client application to interceptors. To "reverse" the direction, the application needs to set up a value that is mutable, like AtomicReference or a callback function, and then the interceptor could interact with that value.
If there may be a noticeable delay between when the server responds with the headers and the first message, then things get more complex. The code calling sayHello():
CompletableFuture<Boolean> future = new CompletableFuture<>();
Iterator<String> stream = blockingStub
.withOption(SomeHeaderInterceptor.SOME_HEADER, future)
.sayHello();
// wait for the sayhello active header
boolean isActive = future.get();
And then in the interceptor:
private static final String FULL_METHOD_NAME =
//"helloworld.Greeter/SayHello";
GreeterGrpc.getSayHelloMethod().getFullMethodName();
public static final CallOptions.Key<CompletableFuture<Boolean>> SOME_HEADER =
CallOptions.Key.create("some_header_active", CompletableFuture.completedFuture(false));
private static final Metadata.Key<String> SAYHELLO_ACTIVE_HEADER =
Metadata.Key.of("some_header_active", Metadata.ASCII_STRING_MARSHALLER);
#Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions callOptions, Channel channel) {
CompletableFuture<Boolean> future = callOptions.getOption(SOME_HEADER);
if (!methodDescriptor.getFullMethodName().equals(FULL_METHOD_NAME)) {
future.complete(false);
return channel.newCall(methodDescriptor, callOptions);
}
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(channel.newCall(methodDescriptor, callOptions)) {
#Override
public void start(Listener<RespT> responseListener, Metadata headers) {
super.start(new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(responseListener) {
#Override
public void onHeaders(Metadata headers) {
if (!headers.containsKey(SAYHELLO_ACTIVE_HEADER)) {
// Could also be future.complete(false)
future.completeExceptionally(new Exception("some_header activation missing from header: " + headers));
} else {
future.complete(true);
}
super.onHeaders(headers);
}
#Override
public void onClose(Status status, Metadata trailers) {
// onHeaders() might not have been called, especially if there was an error
if (!future.isDone()) {
future.completeExceptionally(status.asRuntimeException(trailers));
}
super.onClose(status, trailers);
}
}, headers);
}
};
}
If you only need to do validation, not actually delay, then you could avoid the delay and just let the interceptor fail the call if validation fails:
private static final String FULL_METHOD_NAME =
//"helloworld.Greeter/SayHello";
GreeterGrpc.getSayHelloMethod().getFullMethodName();
private static final Metadata.Key<String> SAYHELLO_ACTIVE_HEADER =
Metadata.Key.of("some_header_active", Metadata.ASCII_STRING_MARSHALLER);
#Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions callOptions, Channel channel) {
if (!methodDescriptor.getFullMethodName().equals(FULL_METHOD_NAME)) {
return channel.newCall(methodDescriptor, callOptions);
}
// We use context to cancel since it is thread-safe, whereas ClientCall.cancel is not
CancellableContext context = Context.current().withCancellation();
class ValidatingListener extends ForwardingClientCallListener<RespT> {
private Listener<RespT> responseListener;
public ValidatingListener(Listener<RespT> responseListener) {
this.responseListener = responseListener;
}
#Override
protected Listener<RespT> delegate() {
return responseListener;
}
#Override
public void onHeaders(Metadata headers) {
if (!headers.containsKey(SAYHELLO_ACTIVE_HEADER)) {
Listener<RespT> saved = responseListener;
responseListener = new Listener<RespT>() {}; // noop listener; throw away future events
Status status = Status.UNKNOWN.withDescription(
"some_header activation missing from header: " + headers);
context.cancel(status.asRuntimeException());
saved.onClose(status, new Metadata());
return;
}
// Validation successful
super.onHeaders(headers);
}
#Override
public void onClose(Status status, Metadata trailers) {
context.close();
}
}
Context toRestore = context.attach();
try {
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(channel.newCall(methodDescriptor, callOptions)) {
#Override
public void start(Listener<RespT> responseListener, Metadata headers) {
super.start(new ValidatingListener(responseListener), headers);
}
};
} finally {
context.detach(toRestore);
}
}
How to retrieve the session ID from Spring Websocket on initial handshake and to be used later on?
Goal
The Goal is whenever a Websocket client connects to the websocket server. The websocket client will pass in a parameter. It will pass in their tenantID. Upon successfull connection to the websocket server. The websocket server usually generates a session ID. What I hope to achieve is associate this websocket sessionID to that specific tenant parameter. And later on, whenever a websocket server will send an update to the that client/tenant. it will send it to that specific tenant via its sessionID that the websocket server has created.
Here is my websocket server configuration..
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//registry.addEndpoint("/client").addInterceptors(new WSHandshakeInterceptor()).withSockJS();
registry.addEndpoint("/agent").addInterceptors(new WSHandshakeInterceptor()).withSockJS();
}
}
WSHandhsakeInterceptor.java
public class WSHandshakeInterceptor implements HandshakeInterceptor {
#Override
public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
return true;
}
#Override
public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {
HttpHeaders header = serverHttpRequest.getHeaders();
String client = header.get("client-id").get(0);
String sessionId = null;
if (serverHttpRequest instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) serverHttpRequest;
HttpSession session = servletRequest.getServletRequest().getSession();
sessionId = session.getId();
System.out.println("Session ID + "+sessionId);
System.out.println("CLIENT ID "+client);
ClassChangeNotificationServiceImpl.clientSessionMap.put(client, sessionId);
}
}
}
Here is how my websocket client connects to the server.
WebSocketClient simpleWebSocketClient = new StandardWebSocketClient();
List<Transport> transports = new ArrayList<>(1);
transports.add(new WebSocketTransport(simpleWebSocketClient));
SockJsClient sockJsClient = new SockJsClient(transports);
stompClient = new WebSocketStompClient(sockJsClient);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
String url = "ws://localhost:8081/agent";
sessionHandler = new MyStompSessionHandler();
try {
WebSocketHttpHeaders wsHTTPheaders = new WebSocketHttpHeaders();
wsHTTPheaders.add("CLIENT-ID","XXXTESTCLIENTXXX");
session = stompClient.connect(url, wsHTTPheaders,sessionHandler).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
MyStompSessionHandler.java
import org.springframework.messaging.simp.stomp.StompFrameHandler;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class MyStompSessionHandler extends StompSessionHandlerAdapter {
private void subscribeTopic(String topic, StompSession session) {
session.subscribe(topic, new StompFrameHandler() {
#Override
public Type getPayloadType(StompHeaders headers) {
System.out.println("HANDLER");
return String.class;
}
#Override
public void handleFrame(StompHeaders headers, Object payload) {
System.out.println("TEST HEKHEk");
}
});
}
#Override
public Type getPayloadType(StompHeaders headers) {
return String.class;
}
/**
* This implementation is empty.
*/
#Override
public void handleFrame(StompHeaders headers, Object payload) {
String resp = (String) payload;
System.out.println("Received responses from websocket server: "+ resp);
}
#Override
public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
subscribeTopic("/user/queue/response", session);
System.out.println("CONNECTEd");
for(Map.Entry<String, List<String>> entry: connectedHeaders.entrySet()) {
System.out.println(entry.getKey()+"S");
}
}
}
Now For the fun part. or what I've been trying to achieve. is I can send an update to the websocket client via this code
this.template.convertAndSendToUser(client, "/queue/reply", message);
Where client is the sessionID that spring has generated. and it will send a message to that specific client only
Question
How do I retrieve the sessionID after a successful handshake?? can I use this sessionID to send specific updates to that client. Here's my code..
Just add this method anywhere in your code to get the session ID after handshake:
#EventListener
private void handleSessionConnected(SessionConnectEvent event) {
String sessionId = SimpAttributesContextHolder.currentAttributes().getSessionId();
}
I can't save data loaded from okhttp. What is wrong in my code. When I try to load data on Log app crashes. Please Help.
public class MainActivity extends AppCompatActivity {
private static final String URL = "https://chroniclingamerica.loc.gov/search/titles/results/?terms=michigan&format=json&page=5";
private String data;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadData();
Log.d("DATA", data);
}
private void loadData() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(URL)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
data = response.body().string();
}
});
}
}
Explanation
The problem is around how your code is being executed (i.e sync vs async).
You call the method loadData() which will not set the class attribute data as you're expecting - it will set the attribute data once it gets a response however that function loadData will not wait for the response (i.e it doesn't block the current thread or execution code.) . Which means on the next line LOG.d("Data", data);, data has not been set, thus is null (and will crash your app).
Solution
If you just want to LOG data, then just move your log statement after you assign it on your onResponse callback.
private void loadData() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(URL)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// Some error has occurred
}
#Override
public void onResponse(Call call, Response response) throws IOException {
processData(response.body().string());
}
});
}
private void processData(String data) {
Log.d("DATA", data);
// To other stuff here given your value data.
}
How to connect Web socket API to android application or any 3rd party library is required? any know know this concept please post
You can use okhttp3 on Android to handle WebSockets!
Example code:
public class EchoWebSocketListener extends WebSocketListener {
#Override public void onOpen(WebSocket webSocket, Response response) {
// called when the connection is opened
}
#Override public void onMessage(WebSocket webSocket, String text) {
//...
}
#Override public void onMessage(WebSocket webSocket, ByteString bytes) {
//...
}
#Override public void onClosing(WebSocket webSocket, int code, String reason){
//...
}
#Override public void onFailure(WebSocket webSocket, Throwable t, Response response){
//...
}
}
Then, in your Activity:
#Override protected onCreate(Bundle savedInstance){
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder().url("ws://echo.websocket.org").build();
EchoWebSocketListener listener = new EchoWebSocketListener();
WebSocket ws = client.newWebSocket(request, listener);
client.dispatcher().executorService().shutdown();
}
I'm developing a chat app using GRPC in which the server receives information from the client and sends it back out to all the clients connected to it. For this, I've used Saturnism's chat-example as a reference. I've replicated the code, the code compiles and runs but the server supposedly never receives any requests from client.
My question is:
Is there a way to enable verbos server side and client side logging in GRPC to see what requests and responses are going in and out & what might be failing?
I'm using the following code for server and client. What might be missing/wrong in the following code that's resulting in no communication between client and server.
WingokuServer.java
public class WingokuServer {
public static void main(String[] args) throws IOException, InterruptedException {
Server server = ServerBuilder.forPort(8091)
.intercept(recordRequestHeadersInterceptor())
.addService(new WingokuServiceImpl())
.build();
System.out.println("Starting server...");
server.start();
System.out.println("Server started!");
server.awaitTermination();
}
WingokuServerSideServiceImplementation:
public class WingokuServiceImpl extends WingokuServiceGrpc.WingokuServiceImplBase {
private static Set<StreamObserver<Response>> observers =
Collections.newSetFromMap(new ConcurrentHashMap<>());
public WingokuServiceImpl() {
System.out.println("WingokuServiceImp");
}
#Override
public StreamObserver<Request> messages(StreamObserver<Response> responseObserver) {
System.out.println("messages");
observers.add(responseObserver);
return new StreamObserver<Request>() {
#Override
public void onNext(Request request) {
System.out.println("Server onNext: ");
System.out.println("request from client is: "+ request.getRequestMessage());
Response response = Response.newBuilder().setResponseMessage("new Message From server at time: "+ System.nanoTime()).build();
for (StreamObserver<Response> observer : observers) {
observer.onNext(response);
}
}
#Override
public void onError(Throwable throwable) {
System.out.println("Server onError: ");
throwable.printStackTrace();
}
#Override
public void onCompleted() {
observers.remove(responseObserver);
System.out.println("Server onCompleted ");
}
};
}
}
WingokuClient:
public class WingokuClient {
public static void main(String[] args) {
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8091).usePlaintext(true).build();
WingokuServiceGrpc.WingokuServiceStub asyncStub = WingokuServiceGrpc.newStub(channel);
StreamObserver<Request> requestStreamObserver = asyncStub.messages(new StreamObserver<Response>() {
#Override
public void onNext(Response response) {
System.out.println("Client onNext");
System.out.println("REsponse from server is: "+ response.getResponseMessage());
}
#Override
public void onError(Throwable throwable) {
System.out.println("Client onError");
throwable.printStackTrace();
}
#Override
public void onCompleted() {
System.out.println("Client OnComplete");
}
});
requestStreamObserver.onNext(Request.newBuilder().setRequestMessage("Message From Client").build());
requestStreamObserver.onCompleted();
channel.shutdown();
System.out.println("exiting client");
}
}
Edit:
There is nothing wrong with the code. It works. I just needed to add awaitTermination to the client's channel because without it just closes the connection between client and server instantly, probably even before the requests go out of the client onto the network. That's why the server never received any requests.
However my question for enabling verbose logging and/or adding some sort of interceptor to the server side still remains unanswered. So I'm looking forward to getting some pointers from experts here.
I found a way to log request and response in both server and client sides by using the Interceptor, it makes the code cleaner.
It is also possible to use sleuth for the tracing as well.
Please use spring:
implementation 'io.github.lognet:grpc-spring-boot-starter'
Server part
You can then use the GRpcGlobalInterceptor annotation
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.grpc.Status;
import org.lognet.springboot.grpc.GRpcGlobalInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.grpc.Metadata.ASCII_STRING_MARSHALLER;
#GRpcGlobalInterceptor
public class GrpcInterceptor implements ServerInterceptor {
private Logger logger = LoggerFactory.getLogger(this.getClass());
public static final Metadata.Key<String> TRACE_ID_KEY = Metadata.Key.of("traceId", ASCII_STRING_MARSHALLER);
#Override
public <M, R> ServerCall.Listener<M> interceptCall(
ServerCall<M, R> call, Metadata headers, ServerCallHandler<M, R> next) {
String traceId = headers.get(TRACE_ID_KEY);
// TODO: Add traceId to sleuth
logger.warn("traceId from client: {}. TODO: Add traceId to sleuth", traceId);
GrpcServerCall grpcServerCall = new GrpcServerCall(call);
ServerCall.Listener listener = next.startCall(grpcServerCall, headers);
return new GrpcForwardingServerCallListener<M>(call.getMethodDescriptor(), listener) {
#Override
public void onMessage(M message) {
logger.info("Method: {}, Message: {}", methodName, message);
super.onMessage(message);
}
};
}
private class GrpcServerCall<M, R> extends ServerCall<M, R> {
ServerCall<M, R> serverCall;
protected GrpcServerCall(ServerCall<M, R> serverCall) {
this.serverCall = serverCall;
}
#Override
public void request(int numMessages) {
serverCall.request(numMessages);
}
#Override
public void sendHeaders(Metadata headers) {
serverCall.sendHeaders(headers);
}
#Override
public void sendMessage(R message) {
logger.info("Method: {}, Response: {}", serverCall.getMethodDescriptor().getFullMethodName(), message);
serverCall.sendMessage(message);
}
#Override
public void close(Status status, Metadata trailers) {
serverCall.close(status, trailers);
}
#Override
public boolean isCancelled() {
return serverCall.isCancelled();
}
#Override
public MethodDescriptor<M, R> getMethodDescriptor() {
return serverCall.getMethodDescriptor();
}
}
private class GrpcForwardingServerCallListener<M> extends io.grpc.ForwardingServerCallListener.SimpleForwardingServerCallListener<M> {
String methodName;
protected GrpcForwardingServerCallListener(MethodDescriptor method, ServerCall.Listener<M> listener) {
super(listener);
methodName = method.getFullMethodName();
}
}
}
Client part
Interceptor:
import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
import static io.grpc.Metadata.ASCII_STRING_MARSHALLER;
#Component
public class BackendInterceptor implements ClientInterceptor {
private Logger logger = LoggerFactory.getLogger(this.getClass());
public static final Metadata.Key<String> TRACE_ID_KEY = Metadata.Key.of("traceId", ASCII_STRING_MARSHALLER);
#Override
public <M, R> ClientCall<M, R> interceptCall(
final MethodDescriptor<M, R> method, CallOptions callOptions, Channel next) {
return new BackendForwardingClientCall<M, R>(method,
next.newCall(method, callOptions.withDeadlineAfter(10000, TimeUnit.MILLISECONDS))) {
#Override
public void sendMessage(M message) {
logger.info("Method: {}, Message: {}", methodName, message);
super.sendMessage(message);
}
#Override
public void start(Listener<R> responseListener, Metadata headers) {
// TODO: Use the sleuth traceId instead of 999
headers.put(TRACE_ID_KEY, "999");
BackendListener<R> backendListener = new BackendListener<>(methodName, responseListener);
super.start(backendListener, headers);
}
};
}
private class BackendListener<R> extends ClientCall.Listener<R> {
String methodName;
ClientCall.Listener<R> responseListener;
protected BackendListener(String methodName, ClientCall.Listener<R> responseListener) {
super();
this.methodName = methodName;
this.responseListener = responseListener;
}
#Override
public void onMessage(R message) {
logger.info("Method: {}, Response: {}", methodName, message);
responseListener.onMessage(message);
}
#Override
public void onHeaders(Metadata headers) {
responseListener.onHeaders(headers);
}
#Override
public void onClose(Status status, Metadata trailers) {
responseListener.onClose(status, trailers);
}
#Override
public void onReady() {
responseListener.onReady();
}
}
private class BackendForwardingClientCall<M, R> extends io.grpc.ForwardingClientCall.SimpleForwardingClientCall<M, R> {
String methodName;
protected BackendForwardingClientCall(MethodDescriptor<M, R> method, ClientCall delegate) {
super(delegate);
methodName = method.getFullMethodName();
}
}
}
Add the interceptor to the channel:
ManagedChannel managedChannel = ManagedChannelBuilder
.forAddress(_URL_, _PORT_).usePlaintext().intercept(backendInterceptor).build();
after many years let me also respond to this question (hoping to be useful for who will have the same problem).
I basically solved by taking as example the response of Shoohei and trying to compress it as much as possible.
Server Interceptor
public class ServerLogInterceptor implements ServerInterceptor {
#Override
public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
ServerCall<ReqT, RespT> listener = new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {
#Override
public void sendMessage(RespT message) {
log.debug("Sending message to cliens: {}", message);
super.sendMessage(message);
}
};
return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(next.startCall(listener, headers)) {
#Override
public void onMessage(ReqT message) {
log.debug("Received message from cliens: {}", message);
super.onMessage(message);
}
};
}}
Client Interceptor
public class ClientLogInterceptor implements ClientInterceptor {
#Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next
) {
return new SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
#Override
public void sendMessage(ReqT message) {
log.debug("Sending message to modules: {}", message);
super.sendMessage(message);
}
#Override
public void start(Listener<RespT> responseListener, Metadata headers) {
super.start(new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(responseListener) {
#Override
public void onMessage(RespT message) {
log.debug("Received message from modules: {}", message);
super.onMessage(message);
}
}, headers);
}
};
}
}
(I'm not sure if I pasted correctly the code, in case just add or remove some parenthesis)
You can turn on the frame logging in the Netty transport. First, create a file called logging.properties. In the file put the following contents:
handlers=java.util.logging.ConsoleHandler
io.grpc.netty.level=FINE
java.util.logging.ConsoleHandler.level=FINE
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
Then start up the Java binary with the jvm flag
-Djava.util.logging.config.file=logging.properties
Also, if you would like to print the message contents or headers as seen on the server, you can create a ServerInterceptor:
https://grpc.io/grpc-java/javadoc/io/grpc/ServerInterceptor.html
You can look at the examples directory on how ServerInterceptor and ClientInterceptor work. There is not pre-existing interceptor that logs the network events.