Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Sunday, 2 October 2011

Android: Implementing logging in your app


How much logging does one need?
How frequently should I log?
(How to use java.util.logging?)

Programming logging in your Android application
Eternal questions about logging and often they don't have a simple answer. Logs are important, even vital sometimes. I don't write anything that does not have some level of logging.
And when we're talking about logging for mobile apps, things can get more complicated.
Why? Well, logs are resources and resources in a mobile device are scarce (that's how I like to think anyway).

By telling the app to log something we are consuming CPU and generating I/O. So if we are iterating a large list something and logging every single iteration, we're probably using a lot of resources.

Which, again could be fine if the user is not being affected by that (if anything we're consuming power). It's all about how the user perceives the app whilst running.
So how to safely implement logging in your Android app?
Here's a few suggestions:

1) Use only 1 log file (do not rollover)
2) Limit it to a size you think is sufficient to capture enough information throughout the app's life cycle
3) collect error logs (by let's say, sending it to your app's remote server) but ONLY with user's agreement
4) log only what you need but with as much information as you can. You'll have to find the right balance for your app.
5) use the logging facilities existing in the SDK.

OK, less talk more code.
First let's learn how to create a logging mechanism using the java.util.logging package (that's right, not Android specific).

The java logging is very flexibly but basically we need 3 things
- a Logger object;
- a log handler;
- a log formatter;

the most simple combination of this 3 is used in the code snippet below

Logger myAppLog=Logger.getLogger("myAppLog"); FileHandler logHandler=new FileHandler("path_to_log.file",false); SimpleFormatter formatter=new SimpleFormatter(); logHandler.setFormatter(formatter); myAppLog.addHandler(logHandler);

The code uses a file as the output for the log messages and a simple text formatter.  By default the log file is in XML. You can write your own formatters just by extending one of the formatting classes.

We are done with the basic stuff, just call myAppLog.log(...), myAppLog.severe(...) or myAppLog.warning(...) however you think necessary. More information about these methods can be found here.

There are however a few details we must observe. All in this line of code

FileHandler logHandler=new FileHandler("path_to_log.file",false);

First the path to the log file. I recommend using the internal memory. I know, less space but has a faster access time. You can use methods like Context.getDir() to properly set a location for your log file.

The second parameter (boolean true) tells the log handler that we don't want to append, i.e, a new file is created every time.

Another thing is the size and number of log files. Remember that I suggested not rolling logs over and limiting the size? Well, we can't do that with the construction above.
For that we need to change that line to

FileHandler logHandler=new FileHandler("path_to_log.file", 100*1024, 1, false);

here we're telling the handler to limit the file to 100kb (100*1024) and to keep only 1 log file, always creating a new one.

Simple isn't it?
Let people know if you like this ;)


---
Programming tricks and tips for android developers

Sunday, 18 September 2011

Android: Sending emails without user intervention (Using Javax Mail API).

Android API doesn't have support for any email protocols but the good news is that there's a javax implementation (a very good one by the way) here.
Download here these files:

  • mail.jar
  • additionnal.jar
  • activation.jar

and add them to your Android project as external jars. To do that in Eclipse, open the project properties (right click on the project name and click properties) and select Java Build Path. Click on the tab Libraries and them Add External JARs. Select the downloaded files and that's it.


Here's a simple example to programmatically send emails using SMTP with authentication but NO SSL/TLS:

public class MySMTPSendMail extends javax.mail.Authenticator {

  private String mUserName;
  private String mPassword;
  private String mHostName;

  public void sendEmailTo(String user, String password, String hostname, String recipient, String body)  throws AddressException, MessagingException{

    mUserName=user;
    mPassword=password;
    mHostName=hostname;

    Properties props = getProperties();


    // this object will handle the authentication
    Session session=Session.getInstance(props,this);
    MimeMessage emailMessage=new MimeMessage(session);
    BodyPart msgBody=new MimeBodyPart();
    MimeMultipart bodyMultipart=new MimeMultipart();


    emailMessage.setFrom(new InternetAddress(mUserName));
    emailMessage.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(recipient));  

    emailMessage.setSubject(body);    
    msgBody.setText(body);   
    bodyMultipart.addBodyPart(msgBody);
    emailMessage.setContent(bodyMultipart);

    Transport.send(emailMessage);
  }

  private Properties getProperties(){
    Properties props = new Properties(); 
   
    props.put("mail.smtp.host", mHostName);   
    props.put("mail.smtp.auth", "true");           
    // default SMTP port
    props.put("mail.smtp.port", "25"); 
  }

  @Override 
  public PasswordAuthentication getPasswordAuthentication() { 
    return new PasswordAuthentication(mUserName, mPassword); 
  } 
}

To send emails using SSL encryption, just change the method getProperties() to something like

  private Properties getProperties(){
    Properties props = new Properties(); 
   
    props.put("mail.smtp.host", mHostName);   
    props.put("mail.smtp.auth", "true");           
    // default SMTP over SSL port
    props.put("mail.smtp.port", "465"); 
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); 
    props.put("mail.smtp.socketFactory.fallback", "false"); 
  }


To send emails using TLS encryption (e.g, live.com) change the method getProperties() to

  private Properties getProperties(){
    Properties props = new Properties(); 
   
    props.put("mail.smtp.host", mHostName);   
    props.put("mail.smtp.auth", "true");           
    // default SMTP over SSL port
    props.put("mail.smtp.port", "465"); 
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.starttls.enable", "true");   
  }

Good luck!! ;)