I am using Log4j to log data in my android application. I have configured the log4j with the help of the following class, but the log files are not getting created.
console logging is enabled, maxfilesize and maxbackupsize are also good. please let me know what i am missing here.
public class ConfigureLog4J {
static LogConfigurator logConfigurator = new LogConfigurator();
private static final int maxFileSize = 1024 * 5; // 100KB
public static final int maxBackupSize = 2; // 2 backup files
public static final String LOG_FILE_NAME = "bitzer.log";
private static HashMap<Integer, Level> logLevelMap = new HashMap<Integer, Level>();
static {
logLevelMap.put(0, Level.OFF);
logLevelMap.put(1, Level.ERROR);
logLevelMap.put(2, Level.INFO);
logLevelMap.put(3, Level.WARN);
logLevelMap.put(4, Level.DEBUG);
logLevelMap.put(5, Level.ALL);
}
public static void startWithLogLevel(int logLevel) {
logConfigurator.setFileName(getLogFileName());
logConfigurator.setRootLevel(getLevelFromInt(logLevel));
logConfigurator.setUseFileAppender(true);
logConfigurator.setUseLogCatAppender(isConsoleLoggingEnabled());
logConfigurator.setMaxFileSize(getMaxFileSize());
logConfigurator.setMaxBackupSize(maxBackupSize);
// Set log level of a specific logger
// logConfigurator.setLevel("org.apache", Level.ERROR);
logConfigurator.setResetConfiguration(true);
logConfigurator.configure();
}
private static long getMaxFileSize() {
return CompanySettings.getInstance().getValueAsInteger(R.string.max_log_size);
}
private static boolean isConsoleLoggingEnabled() {
return CompanySettings.getInstance().getValueAsBoolean(R.string.consoleLoggingEnabled);
}
private static Level getLevelFromInt(int newLogLevel) {
return logLevelMap.get(newLogLevel);
}
public static String getLogsDirectory() {
if(AppData.getInstance().getContext()!=null)
{ String packageName = AppData.getInstance().getContext().getPackageName();
System.out.println("sundeep package name is not null and it's"+packageName);
return "data/data/" + packageName + "/logs/";
}
return null;
}
public static String getLogFileName() {
return getLogsDirectory() + LOG_FILE_NAME;
}
}
SLF4J Overview
I highly recommend you use SLF4J, which is log4j's "older brother" of sorts; the same developers who made log4j made SLF4J to address the shortcomings of log4j.
The difference is, whereas log4j is a full-fledged logging framework, SLF4J is a facade which you use directly in your Java code. The facade aspect allows you to plugin a concrete logging implementation — such as log4j, logback, Android's Log utility, etc. — at runtime.
It allows you to write code that can be used between different projects without having to go through your code and convert your logging statements to use the target project's logging framework. If you have several thousand lines of code which use log4j, but the target you're importing them into uses Apache Commons logging, you'll soon find yourself with a headache if you manually make the changes... even with the assistance of a capable IDE.
Using log4j in Android
There's a great Android library for logging to log4j — as well as many other logging frameworks as well — called android-logging-log4j. Check out the very excellent section on "Using log4j over slf4j", which is the route I take in my Android projects.
Examples from my own projects
Here are some examples from my own projects, such as my Awnry News & Weather app. (Yeah, shameless plug :P)
Required JARs on classpath
Basically these are the JARs I'll typically have in my project's classpath (version numbers vary as new releases come about, of course).
android-logging-log4j-1.0.3.jar
log4j-1.2.17.jar
slf4j-api-1.7.6.jar
slf4j-log4j12-1.7.6.jar
Instantiating a class's logger
And here's how I instantiate my general logger in each of my classes that require logging:
package com.awnry.android.naw;
...
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
public class NawApplication extends Application
{
private static final Logger log = LoggerFactory.getLogger(NawApplication.class);
As you can see, I'm only referencing SLF4J's Logger and LoggerFactory interfaces, even though the actual logging may eventually be accomplished using log4j or Android's Log.
That's the beauty of SLF4J's facade design: You aren't tied down to any specific logging implementation/framework; you can change your mind in the future without having to change a line of your code. If you're using log4j over SLF4J now, but in the future you want to use the Apache Commons Logging framework all you have to do is switch out the SLF4J-to-log4j bridge to a SLF4J-to-ACL bridge, and none of your Java code will be any wiser as it only calls SLF4J interfaces. The time-honored adage to code to an interface, not an implementation holds true once again, and SLF4J is a superb example of that.
Configuring the Android app's logging
In my Application.onCreate() method, I configure my logging like this:
#Override
public void onCreate()
{
...
String logFile = getFilesDir().getAbsolutePath() + File.separator + "logs" + File.separator + "debug.log";
log.info("Application log file: " + logFile);
LogConfigurator logConfigurator = new LogConfigurator(logFile, Level.TRACE);
logConfigurator.configure();
...
}
This part is actually optional, I believe. In my case I do this because I use the ACRA library to help catch unexpected program crashes and report the details back to me for debugging, so you might not need to define your android-logging-log4j's LogConfigurator as I do here.
Why you are using log4j.
There are efficient Log utility is available specially designed for android.
Use LogCat. Its very simple to use and standard way of putting log in your android app.
Related
I seen this link: https://azure.microsoft.com/en-us/documentation/articles/storage-java-how-to-use-table-storage/
but i have problem with connection string when run app with android.
This is my connection:
public static final String storageConnectionString = "DefaultEndpointsProtocol=http;"
+ "AccountName=demoeeg;"
+ "AccountKey=aDJtpWT2/UjBjrwt3BprpujNLNueTl5CjHkik6X6ELdLjGCU5jbnwXz8YCHnQs6wVO6YvY5sGUc7xWon/Iv3ug==";
and in other class I set:
private static final String USE_DEVELOPMENT_STORAGE_NAME = "UseDevelopmentStorage";
Where is my error?
Don't set use development storage. This means use the storage emulator -- and that's not going to work with Android. I'd recommend checking out the samples in the azure-storage-android repo which will give you some ideas on how to configure your application. Then, you can pull any code snippets you'd like from the how-to which will also give you more conceptual information.
Jake Wharton mentioned this library in a recent talk and it looks like a great way to avoid a load of boilerplate so I gave it a go. But without any success.
https://github.com/SimonVT/schematic
Below is the definition of the content provider with the annotation attached and the manifest provider element. The issue is that Android Studio does not like the provider definition because the content provider class does not extend ContentProvider.
Caused by: java.lang.ClassCastException: com.myapp.SchematicContentProvider
cannot be cast to android.content.ContentProvider
What am I missing? It could be related to android-apt which I am not using (Schematic recommends it but does not seem to require it) - when I try using android-apt I get a VerifyError so had to remove it from the build.
AndroidManifest.xml
<provider
android:name="com.myapp.SchematicContentProvider"
android:authorities="com.myapp.provider"
android:exported="false" />
And the class definition:
import net.simonvt.schematic.annotation.ContentProvider;
import net.simonvt.schematic.annotation.ContentUri;
import net.simonvt.schematic.annotation.TableEndpoint;
#ContentProvider(authority = SchematicContentProvider.AUTHORITY, database = SchematicDatabase.class)
public class SchematicContentProvider {
public static final String AUTHORITY = "com.myapp.provider";
interface Path {
String ROUTES = "routes";
}
#TableEndpoint(table = SchematicDatabase.ROUTES) public static class Routes {
#ContentUri(path = Path.ROUTES, type = "vnd.android.cursor.dir/list", defaultSort = SchematicRouteColumns.TITLE + " ASC")
public static final Uri ROUTES = Uri.parse("content://" + AUTHORITY + "/" + Path.ROUTES );
}
}
I've looked through the Schematic sample app (the code snippets in the readme are partial) but I can't see what I've missed. I'm not sure how to confirm that the code generation is working, how do I check? I looked under build but I only see BuildConfig under the Schematic package name.
It's a shame it's not working for me, it has great potential.
You aren't declaring the right ContentProvider.
You have to declare the generated one in the Manifest.
I should like this :
<provider
android:name=".yourOptionalPackage.generated.SchematicContentProvider"
android:authorities="com.myapp.provider"
android:exported="false" />
If your IDE (Android Studio/IntelliJ) shows red warning, just click on the Make Project button to generate the code.
If it's still not working, include apt-libs in your project (worth it), and to save even more time, use this awesome library also based on apt-libs ;)
Let me know in the comments if I solved your problem or not, and if you need help configuring your gradle file.
You receive this error because com.myapp.SchematicContentProvider is your class with annotations and isn't a generated ContentProvider (which will have the same name).
Louis Cognault provided a correct answer, but it worth to mention that Schematic has a special parameter packageName for #ContentProvider and #Database annotations. packageName defines where generated classes will be placed. It let's you to clarify creation of AndroidManifest.xml.
Provider definition class:
#ContentProvider(
authority = SchematicContentProvider.AUTHORITY,
database = SchematicDatabase.class,
packageName = "com.myapp.providerpackage")
public class SchematicContentProvider {
...
}
Database definition class:
#Database(
version = SchematicDatabase.VERSION,
packageName = "com.myapp.providerpackage"
)
public class SchematicDatabase{
public static final int VERSION = 1;
...
}
AndroidManifest.xml:
<provider
android:name="com.myapp.providerpackage.SchematicContentProvider"
android:authorities="com.myapp.provider"
android:exported="false" />
Sorry for lame and easy question but I failed to find an answer to it.
Every time I print something to the System.Diagnostics.Debug.WriteLine I have my message tripled:
System.Diagnostics.Debug.WriteLine("test");
Output:
[0:]
test
[0:] test
10-22 19:57:13.981 I/mono-stdout( 1026): test
I'm stick to System.Diagnostic.Debug because I write messages from both UI part (monodroid) and business logic (PCL)
Is there any way to descrease level of debug noise of Xamarin.Android?
Thank you for any suggestions.
Make your own little abstraction. We have the same issue in our project, this little Interface helps:
public interface ILogger
{
void Write(LogLevel level, String tag, String message);
}
Then you have your Loggers for each platform, for example:
public class AndroidLogger: ILogger
{
public void Write(LogLevel level, string tag, string message)
{
Android.Util.Log.WriteLine(ConvertLogLevel(level), tag, message);
}
}
You inject the logger in the iOS/Android project and you can even create fancy logger like e.g. a nice file-logger for iOS:
#if DEBUG
LOG.AddLogger(new TouchFileLogger());
LOG.AddLogger(new ConsoleLogger());
#endif
The LOG-class is static and needs not to know about the implementations, thats why it can be easily used in your shared PCL library.
Hope that helps, despite your problem might be solved by now ;-)
You can use Android.Util.Log instead, this greatly decreases it. It also has different levels of logging which you can filter in logcat.
Info: Log.Info()
Debug: Log.Debug()
Warning: Log.Warn()
Error: Log.Error()
Verbose: Log.Verbose()
and additionally a WriteLine, which does all of the above:
Log.WriteLine()
I'm attempting to follow the example tutorial at https://developers.google.com/eclipse/docs/endpoints-addentities and I'm stuck figuring out how to get the GameEndpoint.Builder class to generate within Eclipse.
After following this and generating the cloud endpoints as described, I have a GameEndpoint class created, but there is no GameEndpoint.Builder class. So obviously I have this error
GameEndpoint.Builder cannot be resolved to a type
I'm stumped at this point. How do I generate the GameEndpoint.Builder class within Eclipse, or what would prevent it?
Code
public class NewGameTask extends AsyncTask<Context, Integer, Long> {
protected Long doInBackground(Context... contexts) {
GameEndpoint.Builder endpointBuilder = new GameEndpoint.Builder(
AndroidHttp.newCompatibleTransport(), new JacksonFactory(),
new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) {
}
});
GameEndpoint endpoint = CloudEndpointUtils.updateBuilder(
endpointBuilder).build();
try {
Game game = new Game();
game.setStart(Calendar.getInstance());
Game result = endpoint.insertGame(game);
} catch (IOException e) {
e.printStackTrace();
}
return (long) 0;
}
}
I figured out my issue after watching this video from Google I/O 2013 which is using Android Studio, but it was the same thing as Eclipse mostly.
My mistake in following https://developers.google.com/eclipse/docs/endpoints-addentities was that you need to put your entity class into the MyApp-AppEngine project and NOT your MyApp project.
That was the source of confusion. In case it helps those in the future, here is a short breakdown of what I did.
Put the Entity class you want to add to App Engine into your MyApp-AppEngine project.
Right click your class and go to Google > Generate Cloud Endpoint Client Library
Right click your MyApp-AppEngine project and go to Google > Generate Cloud Enpoint Client Library
New references will be made in your MyApp project which you reference in your project for usage.
Note This answer is based on Android Studio, but am sure it's pretty much the same as Eclipse.
I also had this issue but later found the cause.Turns out I was importing the Endpoint class I generated instead of the endpoint Api package. Let me be clear.When you add the endpoint module to your project, you get the MyBean and MyEndpoint classes in the endpoint package. If you take a look at the guide to connecting your client to your backend, the EndpointsAsyncTask class uses:
private static MyApi myApiService = null;
Note how it uses MyApi instead of MyBean Now I was wondering where it got that from but I just have to take a look at my backend libraries:
The library marked 1 is the library first added to your project when you follow the guide previously mentioned. When I added a new class Student and autogenerated the cloud endpoint class, the second library was also added.
Long, boring story short; It is this library you should be importing and not the class.
import com.package-name.backend.studentApi.StudentApi;
and then using:
private static StudentApi myApiService = null;
...
StudentApi.Builder builder = new StudentApi.Builder(...)
instead of:
import com.package-name.backend.StudentEndpoint;
...
private static StudentEndpoint myApiService = null;
StudentEndpoint.Builder builder = new StudentEndpoint.Builder(...)
I got the same problem in Android Studio. I generated my Endpoint class from my entity java bean but when creating the AsyncTask, now way to get the Builder.
Actually (if I take a Game java bean like you) the Builder is not depending on the GameEndPoint but on the generated GameApi class.
In other words, I had to add these two imports in the AsyncTask class:
import com.examplepackage.backend.gameApi.GameApi;
import com.examplepackage.backend.gameApi.model.Game;
while the Game java bean that you wrote and the generated GameEndpoint are under package com.examplepackage.backend
Could you guys please help me why I'm having this exception?
I extracted RequestFactory proxies and context interfaces into separate jar so I can use it both in GWT client and Android client (details are here)
Unfortunately RF throws an exception on the server in very first call. The exception is:
com.google.web.bindery.requestfactory.server.UnexpectedException: No RequestContext for operation LPZEK7DlYkoG1$NQ5MjHlmuRChk=
at com.google.web.bindery.requestfactory.server.ServiceLayerDecorator.die(ServiceLayerDecorator.java:216)
at com.google.web.bindery.requestfactory.server.ResolverServiceLayer.resolveRequestContext(ResolverServiceLayer.java:154)
Below is my factory interface. As you can see I had to replace Service annotations with ServiceName because I didn't want to compile all custom locators with Guice injections to jar that will go on mobile devices.
public interface AdminRequestFactory extends RequestFactory
{
// #Service(value = UserServiceDao.class, locator = InjectingServiceLocator.class)
#ServiceName(value = "com.blah.courierApp.server.dao.UserServiceDao", locator = "com.blah.courierApp.server.inject.InjectingServiceLocator")
public interface GaeUserServiceContext extends RequestContext
{
public Request<String> createLogoutURL(String destinationURL);
public Request<GaeUser> getCurrentUser();
}
// #Service(value = OrderDao.class, locator = InjectingServiceLocator.class)
#ServiceName(value = "com.blah.courierApp.server.dao.OrderDao", locator = "com.blah.courierApp.server.inject.InjectingServiceLocator")
public interface OrderRequestContext extends RequestContext
{
Request<List<OrderProxy>> listAll();
Request<Void> delete(Long id);
Request<Void> createOrder(OrderProxy order);
Request<OrderProxy> findOrderById(long id);
Request<Void> updateOrderState(long id, StateType newStateType);
}
GaeUserServiceContext contextUserService();
OrderRequestContext contextOrder();
}
When I compiled it RF Annotation Tool gave following warning:
Cannot fully validate context since domain type com.blah.courierApp.server.dao.UserServiceDao is not available.
You must run the ValidationTool as part of your server build process.
Add #SuppressWarnings("requestfactory") to dismiss.
So when the exception thrown under the debugger on the server I see that instance of com.google.web.bindery.requestfactory.vm.impl.Deobfuscator has empty operationData field which is being initialized by DeobfuscatorBuilder class that was generated by RequestFactory annotation tool.
So... I decompiled that class and found this:
public final class AdminRequestFactoryDeobfuscatorBuilder extends Deobfuscator.Builder
{
public AdminRequestFactoryDeobfuscatorBuilder()
{
withRawTypeToken("w1Qg$YHpDaNcHrR5HZ$23y518nA=", "com.google.web.bindery.requestfactory.shared.EntityProxy");
withRawTypeToken("8KVVbwaaAtl6KgQNlOTsLCp9TIU=", "com.google.web.bindery.requestfactory.shared.ValueProxy");
withRawTypeToken("FXHD5YU0TiUl3uBaepdkYaowx9k=", "com.google.web.bindery.requestfactory.shared.BaseProxy");
withRawTypeToken("5vjE9LUy$l0uvi4kMYpS3JA1WEE=", "com.blah.shared.model.GaeUser");
withRawTypeToken("8KVVbwaaAtl6KgQNlOTsLCp9TIU=", "com.google.web.bindery.requestfactory.shared.ValueProxy");
withRawTypeToken("5a7OV4PSV$1xemsooKLfEQ4g5yY=", "com.blah.shared.proxies.OrderProxy");
withRawTypeToken("neR_xIhE5oZsc0HbnkAMa8A88yw=", "com.blah.shared.proxies.OrderStateProxy");
withRawTypeToken("t6gMQWDROJnYvqYhNURV8pd$sn4=", "com.blah.shared.proxies.OrganizationProxy");
withRawTypeToken("1o45xgS$5bIkBKF4wlR8oMw_FSo=", "com.blah.shared.proxies.PersonProxy");
withRawTypeToken("FXHD5YU0TiUl3uBaepdkYaowx9k=", "com.google.web.bindery.requestfactory.shared.BaseProxy");
}
}
It didn't generated tokens for factory. Therefore there are no calls to Deobfuscator.Builder.withOperation because of which my server can't find context when calls comes from the client.
Questions are:
Why doesn't RequestFactory Annotation Tool generate tokens for factory (operations) ?
How can I fix it ?
Well, it was pretty tricky... But debugging in RF Annotation Tool helped :)
Turns out you have to have domain classes that you refer to in #ServiceName in classpath of RF Annotation Processor. It creates chicken-and-egg problem. You have to compile SharedClasses module to compile main module but you have to compile domain classes from main module to compile SharedClasses module.
Here is what I did:
Disabled RF annotation processing for SharedClasses module.
In RF annotation processor of main module I explicitly specified RF factory that has to be processed using parameter rootOverride = com.blah.shared.factories.AdminRequestFactory
It sucks that I have hardcoded full qualified class name in project settings though.
If you guys know more elegant method please let me know.
I too hit the same problem. Basically I have 3 GWT modules 1. Main module and in the second module I have the requestFactory, server domain classes and the client side proxy values. I am pretty much sure that your solution is what I need to put in place. However I am confused how to specify the rootOverride in the maven build phase. Any pointers in the structure of pom.xml would be immensely helpful.