How to enable log4j in this Grizzly/Jersey application - log4j

I'm not using any XML configuration and am doing everything at run time.
My application runs and Jersey my API works, but I'm not seeing any logs being written. I expect to see something like INFO: [MyApp] Initializing log4j from [classpath:environment-${MY_ENVIRONMENT}.properties]
when this application boots up to confirm it's seeing the log4j configuration.
I've avoided using log4j.properties since I want different logging configuration per my application's environment.
How can I get this application writing logs via my log configuration?
My main class is:
import com.sun.jersey.api.container.grizzly2.GrizzlyServerFactory;
import com.sun.jersey.api.core.PackagesResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.api.json.JSONConfiguration;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.servlet.WebappContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.web.context.ContextLoaderListener;
...
protected static HttpServer startServer() throws IOException {
ResourceConfig rc = new PackagesResourceConfig("com.company.product.api.resources");
Map<String,Boolean> features = rc.getFeatures();
features.put(JSONConfiguration.FEATURE_POJO_MAPPING, true);
return GrizzlyServerFactory.createHttpServer(BASE_URI, rc);
}
public static void main(String[] args) throws IOException {
//Without this, ApplicationContextProvider has no context
AnnotationConfigApplicationContext annotationCtx = new AnnotationConfigApplicationContext(Config.class);
//The only reason this is here is because I think I need it for log4j config
WebappContext ctx = new WebappContext("API", "/");
//enable log4j configuration
ctx.addListener("org.springframework.web.util.Log4jConfigListener");
ctx.addContextInitParameter("log4jConfigLocation", "classpath:environment-${MY_ENVIRONMENT}.properties");
//enable annotation configuration so we can avoid XML
ctx.addContextInitParameter("contextClass", "org.springframework.web.context.support.AnnotationConfigWebApplicationContext");
ctx.addContextInitParameter("contextConfigLocation", "com.company.product.api");
//allow spring to do all of it's stuff
ctx.addListener(ContextLoaderListener.class);
HttpServer httpServer = startServer();
System.in.read();
httpServer.stop();
}
In environment-production.properties, all configuration is properly being used, except for log4j:
# Define the root logger with appender file
log4j.rootLogger = DEBUG, FILE
# Define the file appender
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender
# Set the name of the file
log4j.appender.FILE.File=/var/log/productionApi/productionApi.log
# Set the immediate flush to true (default)
log4j.appender.FILE.ImmediateFlush=true
# Set the threshold to debug mode
log4j.appender.FILE.Threshold=debug
# Set the append to false, should not overwrite
log4j.appender.FILE.Append=true
# Set the DatePattern
log4j.appender.FILE.DatePattern='.' yyyy-MM-dd-a
# Define the layout for file appender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n

Based on the example, you didn't call ctx.deploy(HttpServer). If you don't do that, then the ServletContext listener you've defined won't be invoked (note: it doesn't matter if you call deploy before or after the server has started).

You may pass log4j.configuration system property to do the trick.
For example:
java -Dlog4j.configuration=environment-production.properties

Related

Azure App Functions: How to inject a singleton service in a class that is not the function/Component?

Azure App Functions 3.0
I am attempting to log activities and errors from an internal class used by functions but the logs are not correct written, since I cannot instantiate/find the service binded to the correct "ILogger" (the one naturally injected in constructors and functions).
I do not want to pass down the Logger instance through classes from the entry point, but inject it correctly.
Tried new LoggerFactory() with no success.
var loggerFactory = new LoggerFactory();
var logger = loggerFactory.CreateLogger("InfoLogger");
logger.LogInformation("Please, log this information!");
Tried ActivatorUtilities.CreateInstance() with Ninject registering the service provider associated with the logger at startup with no success.
// Startup.cs
NinjectKernel._kernel
.Bind<IServiceProvider>()
.ToMethod(context => builder.Services.BuildServiceProvider())
.InSingletonScope();
// MyInternalClass.cs
var serviceProvider = NinjectKernel.Get<IServiceProvider>();
var logger = ActivatorUtilities.CreateInstance<ILogger>(serviceProvider);
logger.LogInformation($"Information Ticket: {ticket} | Data: ...");
Any help are welcome!

azure web app loaded from github repo based on spring boot problem

yesterday i linked my github to an azure web app service
my repo built with rest requests and some of them is working with loading data from firestore based databased , i ran it all on localhost on the tomcat embedded server that comes with spring
,got the web app in the air and my post request which getting resource from firebase , the post request got me an internal 500 server so i check the app insights feature to check what exception i get
java.lang.IllegalStateException: FirebaseApp with name [DEFAULT] doesn't exist.
at com.google.firebase.FirebaseApp.getInstance(FirebaseApp.java:165)
at com.google.firebase.FirebaseApp.getInstance(FirebaseApp.java:136)
my init code for fire base is:
package Model;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.util.Objects;
#Service
public class FBInitialize {
#PostConstruct
public void initialize() {
try {
String fileName = "name of json file with Credential.json";
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(Objects.requireNonNull(classLoader.getResource(fileName)).getFile());
FileInputStream serviceAccount = new FileInputStream(file);
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("https://qr-database-my data base url")
.build();
FirebaseApp.initializeApp(options);
} catch (Exception e) {
e.printStackTrace();
}
}
i checked on the logs and i did got the request i just getting this exception is anyone ever encounter
this exception ?
by the way on initiazlizeApp method the getIntstance methood is being called.
Edit:
found where the exception was thrown from :
public static FirebaseApp getInstance(#NonNull String name) {
synchronized(appsLock) {
FirebaseApp firebaseApp = (FirebaseApp)instances.get(normalize(name));
if (firebaseApp != null) {
return firebaseApp;
} else {
List<String> availableAppNames = getAllAppNames();
String availableAppNamesMessage;
if (availableAppNames.isEmpty()) {
availableAppNamesMessage = "";
} else {
availableAppNamesMessage = "Available app names: " + Joiner.on(", ").join(availableAppNames);
}
String errorMessage = String.format("FirebaseApp with name %s doesn't exist. %s", name, availableAppNamesMessage);
throw new IllegalStateException(errorMessage);
}
}
}
The problem may be the source code version on github. Please check build.gradle file under android/app folder.
Add the following line:
apply plugin:'com.google.gms.google-services'
Related Posts:
1. How to solve Exception Error: FirebaseApp with name [DEFAULT] doesn't exist?
2. FirebaseApp with name [DEFAULT] doesn't exist
im working with maven , also i figured it out that its has something with the json file with the google credentials location because repackaging the file changing the root content to BOOT-INF so i took the json file content put it in a String and cast it to Inputstream so the Initializeapp and the init would be independent but it still no joy :(
new update:
now i get a different exception I think its about security
java.lang.IllegalStateException: Could not find TLS ALPN provider; no working netty-tcnative, Conscrypt, or Jetty NPN/ALPN available
agian im working with maven and not on android

Application Insights for WebAPI application

Is it possible to tell Application Insights to use a different InstrumentationKey depending on the request URL?
Our application works with different clients and we want to separate the logs for them in different instances of Application Insights.
Url format: https://webapi.com/v1/{client_name}/bla/bla
It would be great to setup configuration to select InstrumentationKey by client_name from request.
If the goal is to send different telemetry items to different instrumentation key, the correct way to achieve that is by modifying the individual item with a TelemetryInitializer to have the correct ikey.
An initializer like the following:
item.Context.InstrumentationKey = ikey.
This initializer should access HttpContext and decide the ikey dynamically from request route/other params.
Modifying TC.Active is not recommended for this purpose as its a global shared setting.
(This is not a very common use case - but there are teams inside Microsoft who does this for PROD scale apps)
You can do that. If you have a logger, have the ApplicationInsightsKey parameter-ized and pass the Key for the client on every call, or inject it on load if your application is tenant based.
Checkout the Docs here: Separating telemetry from Development, Test, and Production
Microsoft.ApplicationInsights.Extensibility.
TelemetryConfiguration.Active.InstrumentationKey = <App-Insights-Key-for-the-client>
Just change the Application Insights key before logging and it will do the job.
It would be great to setup configuration to select InstrumentationKey
by client_name from request.
You can dynamically select the ikey as per the client_name from the request. First, you need to get the request url, then check the client_name.
To do that, you can add the following code to the Global.asax file:
void Application_BeginRequest(Object source, EventArgs e)
{
var app = (HttpApplication)source;
//get the request url
var uriObject = app.Context.Request.Url.ToString();
if (uriObject.Contains("/client_name_1"))
{
Microsoft.ApplicationInsights.Extensibility.
TelemetryConfiguration.Active.InstrumentationKey = "ikey_1";
}
else if (uriObject.Contains("/client_name_2"))
{
Microsoft.ApplicationInsights.Extensibility.
TelemetryConfiguration.Active.InstrumentationKey = "ikey_2";
}
else
{
Microsoft.ApplicationInsights.Extensibility.
TelemetryConfiguration.Active.InstrumentationKey = "ikey_3";
}
}
The test result:
But I want to say we rarely use 1 more ikeys in one environment. If your goal is to make the data not being cluttered, I suggest you can use only 1 ikey, and then use Kusto query for your purpose.
Thanks to the answers from #cijothomas and #danpop (link) I was able to understand the whole picture.
Step 1: Create custom ITelemetryInitializer (Microsoft Documentation):
public class MyTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
var appKey = CallContext.LogicalGetData("ApplicationKey")?.ToString();
switch (appKey)
{
case "App1":
telemetry.Context.InstrumentationKey = "d223527b-f34e-4c47-8aa8-1f21eb0fc349";
return;
default:
telemetry.Context.InstrumentationKey = "f8ceb6cf-4357-4776-a2b6-5bbed8d2561c";
return;
}
}
}
Step 2: Register custom initializer:
<ApplicationInsights xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
<TelemetryInitializers>
<Add Type="Application.WebAPI.MyTelemetryInitializer, Application.WebAPI"/>
</TelemetryInitializers>
<!--<InstrumentationKey>f8ceb6cf-4357-4776-a2b6-5bbed8d2561c</InstrumentationKey>-->
</ApplicationInsights>
OR
protected void Application_Start()
{
// ...
TelemetryConfiguration.Active.TelemetryInitializers.Add(new MyTelemetryInitializer());
}
Step 3: Make some adjustments to the logger (source code taken from #danpop answer Logger target configuration):
var config = new LoggingConfiguration();
ConfigurationItemFactory.Default.Targets.RegisterDefinition("ai", typeof());
ApplicationInsightsTarget aiTarget = new ApplicationInsightsTarget();
aiTarget.InstrumentationKey = "your_key";
aiTarget.Name = "ai";
config.AddTarget("ai", aiTarget);
LogManager.Configuration = config;
ILogger configuration exmples: Log4Net, NLog, System.Diagnostics

Using NLog LogLevel value from AppSettings configuration file

I need to configure NLog settings from another application, essentially I have a main Application and a Configuration Application and need to set some log settings from the Configuration Application.
I have tried below but minlevel is an enum and is not valid.. :(
<logger name="*" minlevel="${appsetting:MinimumLogLevel}" writeTo="File" />
It would be perfect for this to work, any suggestions?
Thanks
** Updated Answer **
NLog ver. 4.6 added support for using NLog-Config-Variables in minLevel. See https://github.com/NLog/NLog/pull/2709
NLog ver. 4.6.7 added support for adjusting minLevel at runtime, by modifying NLog-Config-Variables and calling ReconfigExistingLoggers(). See https://github.com/NLog/NLog/pull/3184
** Original Answer **
the minlevel attribute is indeed not a Layout, so you can't use layout renderers like `${appsetting}.
You could do it programmatically:
var configuration = LogManager.Configuration;
//TODO find correct rule
var rule = configuration.LoggingRules[0];
//disable all
rule.DisableLoggingForLevel(LogLevel.Trace);
rule.DisableLoggingForLevel(LogLevel.Debug);
rule.DisableLoggingForLevel(LogLevel.Trace);
rule.DisableLoggingForLevel(LogLevel.Info);
rule.DisableLoggingForLevel(LogLevel.Warn);
rule.DisableLoggingForLevel(LogLevel.Error);
rule.DisableLoggingForLevel(LogLevel.Fatal);
var minLevelRaw = System.Configuration.ConfigurationManager.AppSettings["minLevel"];
var minLevel = LogLevel.FromString(minLevelRaw);
//enable correct one
rule.EnableLoggingForLevels(minLevel, LogLevel.Fatal); //enable from minLevel to fatal
LogManager.Configuration = configuration;
or if it should work for all rules, you could use GlobalThreshold:
var minLevelRaw = System.Configuration.ConfigurationManager.AppSettings["minLevel"];
var minLevel = LogLevel.FromString(minLevelRaw);
LogManager.GlobalThreshold = minLevel;

How to congigure log4j property file to print only Listener class logs in the Console?

I am using the Listener Class which is consisting of few log methods as shown below to log for TestNG tests. I want only listener class logs to be printed in my console and Full logs shouls go to the FullLog file. Full logs are moving to the Full log file, but in console am getting both full logs and Listener Class logs. How do i configure the log4j property file for the same.
Listener class:
public class SimpleListener implements ITestListener {
private static Logger m_log = Logger.getLogger(SimpleListener.class);
public void onFinish(ITestContext itestcontext) {
m_log.info("onFinish() is called"); }
public void onStart(ITestContext itestcontext) {
m_log.info("onStart() is called");
}
}
my log4j Property file:
log4j.rootLogger=INFO, FullLogAppender, ConsoleAppender
log4j.logger.TestLog=INFO, BreakPointAppender
#Console Log Appender
log4j.appender.ConsoleAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.ConsoleAppender=org.apache.log4j.ConsoleAppender
log4j.appender.ConsoleAppender.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.appender.ConsoleAppender.Target=System.out
#Full Log Appender
log4j.appender.FullLogAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.FullLogAppender.File=mfgLogs/FullLogs/FullLog.log
log4j.appender.FullLogAppender=org.apache.log4j.RollingFileAppender
log4j.appender.FullLogAppender.layout.ConversionPattern=%d %-5p %c %x- %m%n
log4j.appender.FullLogAppender.Append=false Dec 12 12:41:11 IST 2012
Expected Result in console:
11:29:33,159 INFO SimpleListener:15 - onStart() is called
11:29:50,372 INFO SimpleListener:31 - runTest.....
11:30:23,637 INFO SimpleListener:23 - Failed
11:30:24,402 INFO SimpleListener:12 - onFinish() is called
remove console appender from root logger
log4j.rootLogger=INFO, FullLogAppender
add a logger for your listener
log4j.logger.xxxx.SimpleListener =INFO, ConsoleAppender
xxxx.SimpleListener will be the fully qualified class name of your listener;
if you don't want the listener's log appears in the full log file, set additivity to false
log4j.additivity.xxxx.SimpleListener=false

Resources