3

Consider a wizard generated ASP.NET Core project (NET 6). Add a Google.Cloud.Diagnostics.AspNetCore3 NuGet package and services.AddGoogleDiagnosticsForAspNetCore() to Startup.cs. Let GOOGLE_APPLICATION_CREDENTIALS environment variable point to a path to your service account JSON.

Somewhere in the app (e.g. a controller) add the following:

_logger.LogDebug("Nope");
_logger.LogInformation("Yeah");

Google Cloud Logs Explorer shows only the "Yeah" (no specific filters). My appsettings.json looks like:

"Logging": {
  "LogLevel": {
    "Default": "Debug",
    "System": "Information",
    "Microsoft": "Information"
  }
}

As far as I understand the "Default": "Debug" should work everywhere where a more specific config is missing.

Why am I not seeing the "Nope" being logged? Anything obvious that I'm missing? It's worth mentioning that both Visual Studio Debug Output as well as the Console output show both Nope/Yeah as expected.

wpfwannabe
  • 14,587
  • 16
  • 78
  • 129
  • Please review the [breaking changes](https://cloud.google.com/dotnet/docs/reference/help/breaking-gax2#:~:text=This%20means%20that%20if%20you%20want%20to%20use%20the%20API%20libraries%20targeting%20GAX%20v3%2C%20you%20need%20to%20be%20using%20.NET%20Core%202.0%20or%20.NET%204.6.1%2C%20or%20a%20higher%20version%20of%20either%20of%20these.) of the [Version 3 upgrade to Version 4.](https://cloud.google.com/dotnet/docs/reference/Google.Cloud.Diagnostics.AspNetCore/latest/history#version-400-beta01-released-2020-02-19). Could that version change be the root cause of your issue? – Pit Jan 18 '22 at 12:01
  • @Pit Not sure. I've reviewed your links. The first one seems to talk about GAX which I don't think is indirectly being used by `Google.Cloud.Diagnostics.AspNetCore3` (already on the latest version 4.4.0). Are you saying I should try to downgrade to 3.x? – wpfwannabe Jan 18 '22 at 14:42
  • have you tried to activate tracing: https://cloud.google.com/dotnet/docs/reference/Google.Cloud.Diagnostics.AspNetCore3/latest#tracing – Elyas Esna Jan 19 '22 at 13:54
  • @ElyasEsna Yes. – wpfwannabe Jan 20 '22 at 05:45
  • have you tried with .NET 5 to see if it is a bug on .NET 6? or maybe you need an explicit set on log levels for google diagnostics. – Yılmaz Durmaz Jan 20 '22 at 14:37
  • @YılmazDurmaz Sadly I have to stay on NET6. As for explicit log levels in `appsettings.json`, I have tried it before and it didn't work. – wpfwannabe Jan 20 '22 at 14:51
  • Have you ever tried to set MinimumLogLevel or default level as Verbose if it is exists. – Görkem Hacıoğlu Jan 21 '22 at 19:44
  • @GörkemHacıoğlu If you would be so kind to give an example of what you are talking about. As the question states the default logging level is already set to "Debug" which should be pretty verbose but still nothing is happening. – wpfwannabe Jan 21 '22 at 20:14
  • I might be using the terms wrong, but I imagine the way aspnet reads appsettings.json is "implicit" because you don't need anything else, yet settting the log level parameters by providing new settings into the method by hand becomes "explicit" for you need to find the way how to implement this. – Yılmaz Durmaz Jan 23 '22 at 09:42

2 Answers2

4

Short Answer: Google.Cloud.Diagnostics.AspNetCore3 does not use appsettings.json (at least for now) and one must explicitly set log levels.

Now to the long answer and working code after that.

To add Google Diagnostics to our project we have 3 overloads of ...AddGoogleDiagnosticsForAspNetCore(...) available, and also ...AddGoogle(...) just to use a service we need, such as logging service. (... at the beginning changes depending on dotnet version, examples at the end).

1- In a GCP environment, ...AddGoogleDiagnosticsForAspNetCore() signature is used to set defaults for the Diagnostics. Service details are fetched from GCP.

2- In a GCP environment, ...AddGoogleDiagnosticsForAspNetCore( AspNetCoreTraceOptions, LoggingServiceOptions, ErrorReportingServiceOptions ) signature we can set 3 types of options: AspNet Tracing, Logging Service and Error Reporting Service.

  • For this use case, if we want only logging services, we can either use positional arguments (null,new LoggingServiceOptions{...},null) (last null is not required) or named arguments (loggingOptions: new LoggingServiceOptions{...})
  • There are many to be set in LoggingServicesOptions{...} but just for log level purpose the following will suffice: new LoggingServiceOptions{ Options = LoggingOptions.Create(logLevel: LogLevel.Debug) }.

Now we have come to the important one. Although documentation covers enough of it implicitly, it is not made explicitly clear that this use case will directly set options, not services.

3- Although not explicitly clear, this use is for cases outside GCP or when GCP cannot be set properly(not sure how!?) AddGoogleDiagnosticsForAspNetCore( projectId, serviceName, serviceVersion, TraceOptions, LoggingOptions, ErrorReportingOptions ). This may seem similar to the 2nd signature at first, but it does not set options for services.

  • When one sees Project ID was not provided and could not be autodetected message for 1st or 2nd signature, they have to provide it as a parameter which immediately switches the function to use this 3rd signature.
  • In this case, if we want only logging services, it has to be used in the form of (projectId,null,null,null,LoggingOptions...,null) for positional arguments (last null is not required) or (projectId:"some ID",loggingOptions: LoggingOptions...) for named arguments
  • LoggingOptions... is simply be LoggingOptions.Create(logLevel: LogLevel.Debug) to set log level.

4- Apart from adding these details while adding Google Diagnostics to the services, we can instead add logging options when we set configurations: ...AddGoogle( LoggingServiceOptions{...} ). But in this use, we need to provide a project Id in it; new LoggingServiceOptions{ ProjectId = "some ID", Options = LoggingOptions.Create(logLevel: LogLevel.Debug) }


fill in the ...

dotnet 6 started using new top level statements. so we have following steps to follow.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGoogleDiagnosticsForAspNetCore(
 projectId: "some ID",
 loggingOptions:  LoggingOptions.Create(logLevel: LogLevel.Debug)
);

// or
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddGoogle(
  new LoggingServiceOptions { 
    ProjectId = "some ID",
    Options=LoggingOptions.Create(logLevel:LogLevel.Debug)
  }
);

Since the OP mentions the use of Startup.cs, the project uses the old style so these are the required parts for that.

// inside ConfigureServices
services.AddGoogleDiagnosticsForAspNetCore(
 projectId: "some ID",
 loggingOptions:  LoggingOptions.Create(logLevel: LogLevel.Debug)
);

// or
// before using "UseStartup"
.ConfigureLogging(
  builder => builder.AddGoogle(
    new LoggingServiceOptions { 
      ProjectId = "some ID",
      Options=LoggingOptions.Create(logLevel:LogLevel.Debug)
    }
  )
)

Extra

We can read from the configuration file (top-level format)

var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
builder.Services.AddGoogleDiagnosticsForAspNetCore(
  projectId:config["GCP:ID"],
  loggingOptions:  LoggingOptions.Create(
     logLevel: Enum.Parse<LogLevel>(config["GCP:Logging:LogLevel:Default"]
)));

and add a GCP section in appsettings.json

  "GCP":{
    "ID":"some ID",
    "Logging":{
      "LogLevel":{
        "Default":"Debug"
      }
    }
  }
Yılmaz Durmaz
  • 2,374
  • 12
  • 26
  • 1
    Both answers were useful but this one is a bit more thorough. Even though none of them showed how to do what I wanted (because it is probably just not possible), this answer was more helpful and just more complete. If I could split the bounty in half, I'd gladly do it. Thanks to all contributors. – wpfwannabe Jan 24 '22 at 19:35
  • @wpfwannabe, thank you for the reward. but now I am a bit concerned about the "none of them showed how to do what I wanted" part. From the phrases you use in your question, I thought you were having problems connecting the debug behavior. can you please expand this so I can see what I missed for your use case? – Yılmaz Durmaz Jan 24 '22 at 19:43
  • @wpfwannabe, as for the bounty points, and you already know I liked his answer too, I started a new bounty and will give him 200 points. – Yılmaz Durmaz Jan 24 '22 at 19:55
  • 1
    That may have sounded harsh. In reality I never wanted to overload the question with fine details (configuring Google logging per class) when in reality the very basics failed to work for me. With this in mind, both answers were on the right track and you came on top. So don't feel bad. Your answer was chosen and bounty awarded. If I was truly dissatisfied this never would have happened. So what I really expected is for Google logging to just get plugged in and work just like rest. I hate the fact that Google log level must be set in code and must be the same everywhere. – wpfwannabe Jan 25 '22 at 14:51
  • 1
    An ideal solution would make Google logging work just as Console or Debug providers where one can use configuration to set individual debug levels for various aspects of the app. Even though I was hopeful I must say that this is certainly beyond the scope of the original question. So you did great. – wpfwannabe Jan 25 '22 at 14:55
  • @wpfwannabe thanks for clearing. I guess I understand a bit more of your use case (sorry if not). for now, I can see two possible solutions. A feature request to developer team through their github repo, or writing a custom wrapper service class around it. I don't know your knowledge level but `config["GCP:Logging:LogLevel:Default"]` I wrote as extra might be usefula bit of towards this custom class. in it, you can remove GCP part and use the same config used as default by all other logger: `config["Logging:LogLevel:Default"]`. – Yılmaz Durmaz Jan 25 '22 at 15:48
3

I've downloaded the mentioned package (it's open-source) and checked default logging-options creation:

enter image description here

As you may see the default logLevel is Information.

And as you go through the implementation there's no sign of reading the level from the config - it's simply passed from the options you may specify in the code:

Initial invocation: enter image description here

Service provider registration: enter image description here

Creation of logging provider and options: enter image description here

Creation of options (1st picture) enter image description here

And creation of logger (probably invoked somewhere internally by ASP.NET) enter image description here

The simple answer is Google package doesn't read anything from the appsettings.json by default.

You can set the logging level by using the LoggingOptions:
(Other options omitted for brevity)

builder.Services.AddGoogleDiagnosticsForAspNetCore(loggingOptions: new Google.Cloud.Diagnostics.Common.LoggingServiceOptions
{
    // ... Other required options, e.g. projectId
    Options = Google.Cloud.Diagnostics.Common
        .LoggingOptions.Create(logLevel: LogLevel.Debug
        // ... Other necessary options 
        ),
});
Mr Patience
  • 1,564
  • 16
  • 30
  • Here's also a related issue: https://github.com/googleapis/google-cloud-dotnet/issues/2435 You may also read the logging level from the configuration on your own. – Mr Patience Jan 21 '22 at 22:10
  • I liked your explanation but the code you gave is not working in this form. care to fix? – Yılmaz Durmaz Jan 23 '22 at 02:38
  • @MrPatience Thank you for the detailed answer. So are you saying that one has no fine control over what gets logged from where? Say you have two classes `A` and `B`. Normally you can use `appsettings.json` to control the log level from within each of the classes individually. If I read your response correctly one can only set a single global log level for the entire app. Is that correct? Worst of all this has to be done in the code rather than in the config. – wpfwannabe Jan 23 '22 at 09:00
  • @YılmazDurmaz, can you explain what you mean? Of course you need to specify some other options like `ServiceName` or `Version` or usually `ProjectId`, but it will depend on your particular setup. – Mr Patience Jan 23 '22 at 09:14
  • @MrPatience I think he means that `LoggingServiceOptions` is not convertible to `LoggingOptions`. – wpfwannabe Jan 23 '22 at 09:25
  • @wpfwannabe, I believe that this is only for ASP.NET-related logging providers or the ones from MS / .NET / Azure packages - they usually try to keep the standard. I don't see any clear way to control it per class other than just using appropriate log levels. `GoogleLoggerProvider` is registered as a singleton and uses same options, passed at the beginning, each time it creates the logger. – Mr Patience Jan 23 '22 at 09:29
  • you are not supplying the required parts thus your code makes a false claim it solves the problem. Imagine you are in need of such a code and it throws more errors than you had before, what would you do? Therefore please give a working code fragment or edit it so no one will just copy-paste. – Yılmaz Durmaz Jan 23 '22 at 09:36
  • I don't think my code makes a false claim that it solves the problem - it's purely an example, but it shows how to do it. I updated the code to make more clear. – Mr Patience Jan 23 '22 at 09:52
  • @wpfwannabe, If you really want to specify `LogLevel` by class you could probably write your own wrapper over the `GoogleLoggerProvider` instance, which would override `LogLevel` of each created logger based on settings specified in `appsettings.json`. This could be done with help of Reflection. This is of course a circumvent and a tad cumbersome solution, but could work pretty well if you do it generically. – Mr Patience Jan 23 '22 at 10:03
  • have you make/run your own program to see if it works? this is currently a bounty race, so you need to either copy-paste your working code fragment and/or edit necessary parts. and your edit still does not give that. – Yılmaz Durmaz Jan 23 '22 at 11:02
  • Here is a hint: what does it mean "running on GCP" and what if you dont? how does your code affected? I had my eyes on t his bounty, but really liked you digging in the source code, thus I want to help. but for the same reason, this is as far I say. good luck ;) – Yılmaz Durmaz Jan 23 '22 at 12:41