I'm trying to log some basic gql method details - resolver/operation name and duration. I've started looking at using .AddHttpRequestInterceptor((context, executor, builder, ct)
and getting the info from the builder, but even though I can see it in the debugger, the method name is buried in private members like:
((HotChocolate.Execution.QueryRequestBuilder)builder)._query.Document.Definitions[0].SelectionSet.Selections[0].Name.Value
I'm sure there's an easier and better way to hook into the pipeline to get the method name and log it with the call duration.
I found an article written about GraphQL.Net that uses DefaultGraphQLExecuter -
public class GraphQLExecutorWithDiagnostics<TSchema> : DefaultGraphQLExecuter<TSchema>
which provides an operationName parameter within the
Task<ExecutionResult> ExecuteAsync(
, which looks ideal.
I'll be logging to AppInsights, but that's not relevant for now, I just want to get the info first.
I'm using v11.0.8
What you are looking for is the DiagnosticEventListener
You can just extend this base class and override the methods that you need for you logging.
public class CustomDiagnosticListener : DiagnosticEventListener
{
public override IActivityScope ExecuteRequest(IRequestContext context)
{
return EmptyScope;
}
public virtual IActivityScope ResolveFieldValue(IMiddlewareContext context)
{
return EmptyScope;
}
}
To use this diagnostic listener you have to add it to the schema
services.AddGraphQLServer()
...
.AddDiagnosticEventListener<CustomDiagnosticListener>()
In case you have dependencies that you listener has to reslove you have to reslove them manually:
services.AddGraphQLServer()
...
.AddDiagnosticEventListener<CustomDiagnosticListener>(
sp => new CustomDiagnosticListener(
sp.GetApplicationService<MyDependency>()))
Related
Context: I am trying to capture multiple events in our api using serilog and the elastic search sink, these events include: GET actions(regular web api flow) as well as login attempts (Owin).
I am registering serilog like this:
container.RegisterConditional(
typeof(ICustomLogger),
c => typeof(CustomLogger<>).MakeGenericType(
c.Consumer?.ImplementationType ?? typeof(object)),
Lifestyle.Singleton,
c => true);
I am doing this for Owin registration:
app.Use(async (context, next) =>
{
using (var scope = container.BeginExecutionContextScope())
{
await next.Invoke();
}
});
Then when I call container.Verify(); the logger constructor gets called(as expected).
However when I call the logger from my OAuthAuthorizationServerProvider implementation like this:
var logger = ObjectFactory.GetInstance<ICustomLogger>(); the constructor gets called again, meaning the singleton is not really a singleton anymore, I am totally aware of the service locator antipattern(don't really have much time to refactor that piece right now), what is interesting is that if I change the logger registration to the following (getting rid of the type piece) then only one instance is created:
container.RegisterSingleton(typeof(ICustomLogger), typeof(CustomLogger))
The reason why I am trying to use the first option is because I want to be able to use .ForContext(typeof(T)); for serilog, and in case you are wondering how I am registering the ObjectFactory piece here it is:
Class:
public static class ObjectFactory
{
public static Container container;
public static void SetContainer(Container container)
{
ObjectFactory.container = container;
}
public static T GetInstance<T>() where T : class
{
return container.GetInstance<T>();
}
}
Registration(from my main bootstrapper):
ObjectFactory.SetContainer(container);
So my main question is: Why is only one instance created with RegisterSingleton but multiple are created with RegisterConditional and Lifestyle.Singleton?
The reason multiple instances are created has nothing to do with the fact that you are using your ObjectFactory, but simply because different closed versions of CustomLogger<T> are created:
A CustomLogger<object> is created when resolved as root type (by calling GetInstance<ICustomLogger>()
A CustomLogger<Service1> is created when ICustomLogger is injected into Service1.
Because a CustomLogger<object> is a different type than a CustomLogger<Service1>, it is impossible to have just one instance for both types. They both have to be created. This might seem weird, but consider these two classes:
public class Service1
{
public Service1(ICustomLogger logger) { }
}
public class Service2
{
public Service2(ICustomLogger logger) { }
}
At runtime, considering these two definitions, you want to create object graphs similar to the following:
var s1 = new Service1(new CustomLogger<Service1>());
var s2 = new Service2(new CustomLogger<Service2>());
In the above case, the CustomLoggers are not cached and are, therefore, effectively transients. You might try to rewrite this to the following, but that would not be the same:
ICustomLogger logger = new CustomLogger<Service1>();
var s1 = new Service1(logger);
var s2 = new Service2(logger);
Now both service get the same single instance. However, this means that Service2 gets a CustomLogger<Service1> which is not what you configured. You configured the dependency to be this:
typeof(CustomLogger<>).MakeGenericType(c.Consumer.ImplementationType)
Consequence of this is that when Service2 starts to log, it will look like if the messages are coming from Service1. This would likely be incorrect behavior. Otherwise, you could have simply called RegisterSingleton<ICustomLogger, CustomLogger<Service1>>().
This all means that the Singleton guarantee for a RegisterConditional that uses an implementation-type factory (as in your example) only holds for the specified closed generic type.
Note that RegisterConditional isn't the only part in Simple Injector where you see this behavior. The following registrations do have the same effect:
container.RegisterSingleton(typeof(IFoo<>), typeof(Foo<>));
container.RegisterDecorator(typeof(IFoo<>), typeof(FooDecorator<>), Lifestyle.Singleton);
In both these cases multiple instances of closed generic versions of Foo<T> and FooDecorator<T> can be created, but Simple Injector guarantees that there is only one instance of every closed-generic version of Foo<T>. With RegisterDecorator<T>, however, even that is not guaranteed. Consider this example:
container.Collection.Append<ILogger, Logger1>(Lifestyle.Singleton);
container.Collection.Append<ILogger, Logger2>(Lifestyle.Singleton);
container.RegisterDecorator<ILogger, LoggerDecorator>(Lifestyle.Singleton);
In this case, a collection of ILogger components is registered where each ILogger element will be wrapped with a LoggerDecorator. Because a LoggerDecorator can only depend on either Logger1 or Logger2, but not both, Simple Injector will have to create a new LoggerDecorator instance for each element. If the LoggerDecorator would be cached as a true Singleton, this would be the result:
private static ILogger logger = new LoggerDecorator(new Logger1());
private static loggers = new[] { logger, logger };
As there is only 1 single LoggerDecorator, this decorator depends on Logger1, which means that the collection of loggers only has two elements that both point to the same Logger1 instance. There is no Logger2.
This information is reflected in the following Simple Injector documentation sections:
Aspect-Oriented Programming - Applying Lifestyles to Decorators
Lifetime Management - Generics and Lifetime Management
I was going through spring documentation more specifically handler mapping section and came to know that we can register the handler mapping method at runtime. I understand how it is done but the thing that I am not able to grasp is why do we need such functionality in the first place?
Please refer following code snippet for registering handlers.
#Autowired
public void setHandlerMapping(RequestMappingHandlerMapping mapping, HelloRestController handler)
throws NoSuchMethodException {
RequestMappingInfo info = RequestMappingInfo
.paths("/mycustomapi").methods(RequestMethod.GET).build();
Method method = HelloRestController.class.getMethod("customHandler");
mapping.registerMapping(info, handler, method);
}
Documentation
If someone can explain some use cases where it required then it will be helpful thank you.
I have never used this, but here is one utility I can think of :
As annotations only accept constant expression as parameters, you can't write something like that :
#GetMapping(requestMapping(...)) // The value for annotation GetMapping.value must be a constant expression
public String customHandler(...) {
...
}
But you could write that :
RequestMappingInfo info = RequestMappingInfo
.paths(requestMapping(...))
.methods(RequestMethod.GET)
.build();
In oher words, you could write handlers for URI that are calculated (stored in a configuration file for example).
I am attempting to implement a filter in a micronaut microservice, using the example code documented in Section 6.18 of the documentation:
https://docs.micronaut.io/latest/guide/index.html#filters
I have a HelloWord service that is essentially the same as the service provided on the documentation, with a controller that goes to "/hello" (as documented). I am also using the same TraceService and trace filter that is provided in Section 6.18. I am compiling and running the server without problems.
Unfortunately, the filter is not being engaged when I test the microservice.
I am pretty sure that something is missing in my code, but as I said I am using the same code that is in the example:
TraceService Class
import io.micronaut.http.HttpRequest;
import io.reactivex.Flowable;
import io.reactivex.schedulers.Schedulers;
import org.slf4j.*;
import javax.inject.Singleton;
#Singleton
public class TraceService {
private static final Logger LOG = LoggerFactory.getLogger(TraceService.class);
Flowable<Boolean> trace(HttpRequest<?> request) {
System.out.println("TRACE ENGAGED!");
return Flowable.fromCallable(() -> {
if (LOG.isDebugEnabled()) {
LOG.debug("Tracing request: " + request.getUri());
}
// trace logic here, potentially performing I/O
return true;
}).subscribeOn(Schedulers.io());
}
}
Trace Filter
import io.micronaut.http.*;
import io.micronaut.http.annotation.Filter;
import io.micronaut.http.filter.*;
import org.reactivestreams.Publisher;
#Filter("/hello/**")
public class TraceFilter implements HttpServerFilter {
private final TraceService traceService;
public TraceFilter(TraceService traceService) {
System.out.println("Filter created!");
this.traceService = traceService;
}
#Override
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
System.out.println("Filter engaged!");
return traceService.trace(request)
.switchMap(aBoolean -> chain.proceed(request))
.doOnNext(res -> res.getHeaders().add("X-Trace-Enabled", "true")
);
}
}
The Controller
import io.micronaut.http.annotation.*;
#Controller("/hello")
public class HelloController {
#Get("/")
public String index() {
return "Hello World";
}
}
Note that the controller uses code from Section 2.2 of the documentation:
https://docs.micronaut.io/latest/guide/index.html#creatingServer
I did a number of things to try and see what was happening with the filter, including putting little printouts in strategic parts of the Service and the filter. These printouts are not printing out, which tells me that the filter is not being created or used by Micronaut.
Clearly I am missing somethning. I suspect that there is something I need to do in order to get the system to engage the filter. Unfortunately the documentation just tells how to make the filter, not how to use it in the microservice. Furthermore, there don't appear to be any complete code examples that tell how to make the request system utilize the filter (maybe there is an annotation I need to add to the controller???).
Could someone tell me what I am missing? How do I get the filter to work? At the very least, could someone provide a complete example of how to create the filter and use it in an actual microservice?
Problem solved.
It actually helps a great deal if one puts the filter and service files in the right place. It was late when I made the files and I put them in the test area, not the development area. Once placed in the right place, the filter was properly injected into the microservice.
Sorry for the waste of space here, folks. Is there any way a poster can delete an embarrassing post?
So, our project has recently started using Server Sent Events in ServiceStack. Our projects also log with log4net, using the log4net provider. Now that I've gotten through a couple of components using SSE, I am wondering if anyone else is thinking what I am here...
I typically use the 'DEBUG' level of log4net for a real chatty, 'debug' experience. When I'm on dev servers, or when I'm trying to get to the bottom of an issue... I'll change the logging level to 'DEBUG' and go to town. While I wouldn't run in higher environments using 'DEBUG' - I find that same level of information is what I might be interested in sending to a client. I have some long-running processes in a service, and it communicates with the web dashboard via SSE to report updates. I'm finding that the type of information that I would typically log to 'DEBUG' is generally what I would like to send to my dashboard. As you can then imagine, my code starts to look like this, and in many areas:
var msg = $"Processed {count} records.";
MessageLog.Debug(msg);
ServerEvents.NotifyChannel(channelName, selector, msg);
Seeing this makes me want to create a thin wrapper to enable the message to be sent to either the log, the SSE, or both with a single call. Does this type of setup exist in ServiceStack at present? I realize it's high level and there's details to work out (logging level, channel and selector values) but I have to believe there is some way to simplify this.
There isn't anything built-in, there are a couple ways you could implement this, my preference would be to use an extension method which takes an ILog, e.g:
public static void NotifyChannel(this IServerEvents server,
string channel, string selector, object message, ILog log)
{
if (log.IsDebugEnabled)
log.Debug(message);
server.NotifyChannel(channel, selector, message);
}
Or you could create an adapter IServerEvents class that you can register as a separate dependency, e.g:
container.Register(c =>
new LoggingServerEvents(c.Resolve<IServerEvents>()));
Which logs and delegates API calls to the IServerEvents dependency, e.g:
class LoggingServerEvents : IServerEvents
{
private static ILog Log = LogManager.GetLogger(typeof(LoggingServerEvents));
private IServerEvents sse;
public LoggingServerEvents(IServerEvents sse) => this.sse = sse;
public void NotifyChannel(string channel, string selector, object message)
{
if (Log.IsDebugEnabled)
Log.Debug(message);
sse.NotifyChannel(channelName, selector, message);
}
//...
}
Which you can reference in your Services like a normal dependency that you can use instead of ServerEvents when you want the message to also be logged, e.g:
public class MyServices : Service
{
public LoggingServerEvents LoggingServerEvents { get; set; }
public object Any(MyRequest request)
{
//ServerEvents.NotifyChannel(channelName, selector, msg);
LoggingServerEvents.NotifyChannel(channelName, selector, msg);
}
}
Please find my HomeController and DemoController
class HomeController{
#RequestMapping(value="index")
public void home(){
}
}
class DemoController{
#RequestMapping(value="index")
public void demo(){
}
}
when I try to send a request to index, which one will get executed?
I wanted to know how can we have same request mapping value for multiple controllers
https://stackoverflow.com/a/34590355/2682499 is only partially correct at this point.
You can have multiple controller methods use the same URI so long as you provide Spring enough additional information on which one it should use. Whether or not you should do this is a different question. I would certainly not recommend using the same URI in two separate controller classes to avoid confusion, though.
You can do something like this:
class HomeController{
#RequestMapping(value="/index", params = {"!name", "!foo"})
public List<Something> listItems(){
// retrieve Something list
}
#RequestMapping(value="/index", params = "name")
public List<Something> listItems(String name) {
// retrieve Something list WHERE name LIKE %name%
}
#RequestMapping(value="/index", params = {"!name", "foo"})
public List<Something> listItems(String foo) {
// Do something completely different
}
}
For the full documentation on what is possible when overloading URIs you should reference the #ReqeustMapping documentation: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html. And, specifically https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html#params-- for the section request parameters.
In Spring Web MVC this is not possible. Each mapping must be unique in your context. If not, you will receive a RuntimeException during context initialization.
You cannot even use parameters to differentiate your endpoints because they are not evaluated while searching for a suitable handler (applicable for Servlet environments). From #RequestMapping javadoc:
In a Servlet environment, parameter mappings are considered as restrictions that are enforced at the type level. The primary path mapping (i.e. the specified URI value) still has to uniquely identify the target handler, with parameter mappings simply expressing preconditions for invoking the handler.
Note that you can do the opposite, so multiple URLs can point to the same handler. Have a look at Spring MVC: Mapping Multiple URLs to Same Controller
Unfortunately, this is not possible. The request mapping has to be unique otherwise the application can't determine which method the incoming request should be mapped to.
What you can do instead is to extend the request mapping:
class HomeController{
#RequestMapping(value="home/index")
public void home(){
}
}
class DemoController{
#RequestMapping(value="demo/index")
public void demo(){
}
}