Logging file save to Microsoft Azure part 2

This article is follow of article[Logging file save to Microsoft Azure part 1]. This article explains how to upload file to Microsoft Azure. The file is application log file. So this article explains simple telemetry feature also.

Microsoft Azure Blob Storage provides several type of data storage below.

・Several type of data storage

Even if you used to use log4net or NLog, this article ‘DOES NOT’ explains these formal logging tool, but implements super easy logging instead of it. Because I want to show you that MVC(in this case, MVVM) implementation model is easy to choice for your solution product. Then, it affects very important point in development scenes later for CD/CI or servicing your software as API.

At first, please download the solution file from GitHub to your local pc.

>> previous article’s sample code

And This is the sample code which applied contents of this article.

>> The sample code

・Create a model of log information

Create solution folder named ‘Models’ at root of the solution. And create model class [Log].

The model [Log] class has simple properties [Message],[OccurredTime],[OperatorName],[LogType] and create Type name [LogType] which has types [Default],[Information],[Error],[Operation]

namespace WPFLockdownSample.Models
{
    public class Log
    {
        public string Message { get; set; }
        public DateTime OccurredTime { get; set; }
        public string OperatorName { get; set; }
        public LogType LogType { get; set; }
    }

    public enum LogType
    {
        Default = 0,
        Information = 1,
        Error = 2,
        Operation = 4
    }
}

As Next step, modify App_Startup method of App.xaml.cs to be able to logging. One point which you have to aware in this step, if some data has DateTime type data, you have to consider both when the data is used by local time and is used at Microsoft Azure programmatically. So the data is held as DateTime type better.

void App_Startup()
{
        void App_Startup(object sender, StartupEventArgs e)
        {
            List logs = new List();
            Log log = new Log() 
                        {
                            Message = "checkking app files ...", OccurredTime = DateTime.Now,
                            OperatorName = typeof(App).Name, LogType = LogType.Information
                        };
            logs.Add(log);
            //Check existing of log file.
            //if (logging.ReadLogs().Count == 0)
            //{
            //    [Local account creation] explains how to create these four accounts.
            //    And how to navigate use logon script
            //    CoreApplication.Exit();
            //}
            //else if (logFile.Exists) check current user
            //{
            //    [Desktop UI control] explains how to check current user
            //    if (UserName == "maintenanceOperator") navigate to MaintenanceWindow
            //    if (UserName == "appOperator") quiet this app. This account has specific automatic
            //                                        run application when this account sign in.
            //    if (UserName == "appUser") quiet this app. This account has specific automatic
            //                                        run application when this account sign in.
            //}
        }
}

The type [Log] is in the Namespace [WPFLockdownSample.Models], so add ‘using WPFLockdownSample.Models;’ statement at top of App.xml.cs. ‘List<Log> logs’ holds several logs information while the logs will be written to log file( and the contents of the file will send to Microsoft Azure later).

The [OperatorName] property is used for recording operations of application with [LogType] property. The [Operation]’s value in [LogType] type. In case of this sample code, the message is application information, so use [LogType.Information] and ‘typeof(App).Name’ for the value. if application message occurs in MainPage, use [LogType.Information] and ‘typeof(MainPage).Name’ value. So it will modified to ‘this.GetType().Name’ later, but it’s keep it so far.

・Write log information to log file

To create function of log writing, create solution folder named [Features] and create [DataAccessLayer] class, The class use Json, so please install Json serializer using NuGet. And then create method below.

    public class DataAccessLayer
    {
        public FileInfo LogFile { get; private set; }
        const string appFilesPath = @"c:\WFPLockdownSample";
        DirectoryInfo logFolder = new DirectoryInfo(appFilesPath);
        public DataAccessLayer()
        {
            LogFile = new FileInfo (
                            appFilesPath + @"\" + DateTime.Now.ToString("yyyyMMdd") + "logs.log"
                        );
        }
        public void AppendWriteLogs(List<Log> logs, bool reverse = true)
        {
            if(reverse) logs.Reverse();
            string jsonstring = string.Empty;
            logs.AddRange(ReadLogs());
            using (StreamWriter file = File.CreateText(LogFile.FullName))
            {
                JsonSerializer serializer = new JsonSerializer();
                serializer.Serialize(file, logs);
            }
        }
        public List<Log> ReadLogs()
        {
            List<Log> logs = new List<Log>();
            string jsonstring = string.Empty;
            if (LogFile.Exists) jsonstring = File.ReadAllText(LogFile.FullName);
            if (!string.IsNullOrEmpty(jsonstring))
            {
                logs = JsonConvert.DeserializeObject<List<Log>>(jsonstring);
            }
            return logs;
        }
    }

This logging feature of [DataAccessLayer] class access to local folder, and in the future, other data sources or data service API, so it should be created as ‘partial’ class, it will be modified as partial class later, but it is normal class so far.

This class has public property [LogFile], it set instance at constructor. And provides two features, one is [AppendWriteLogs] method and another is [ReadLogs] method.

[AppendWriteLogs] method is a feature which outputs logs information to log file, [logs] argument is a container of log information which added when it occurred, so log information listed by time series order in [logs] argument, therefore most newest log information should be written at top most of log file. So order of logs information which accepted are reversed as default execution.

Then logs of the log file append to [logs] argument and write back to the log file.

On other hand, [ReadLogs] method provides a feature of read contents of the log file. If log file is not exists or log file has not any contents, it returns blank container of logs information. This state is first time execution of this application. So if log information count of this log container is zero, this application try to create four accounts for operation scenarios.

・Use log functions

To use write log function [AppendWriteLogs] method of the [DataAccessLayer] class, call the [DataAccessLayer] class at top of [App_Startup] method, then use [ReadLogs] method and count logs.

And create log information which scenario was choosen, then write logs information use [AppendWriteLogs] method at end of all step.

public partial class App : Application
{
    DataAccessLayer dataAccessLayer = new DataAccessLayer();
    void App_Startup(object sender, StartupEventArgs e)
    {
        List logs = new List();
        Log log = new Log() 
                {
                        Message = "checkking app files ...", OccurredTime = DateTime.Now,
                        OperatorName = typeof(App).Name, LogType = LogType.Information
                };
        logs.Add(log);
        if (dataAccessLayer.ReadLogs().Count == 0)
        {
            log = new Log()
                {
                        Message = "this exesution is first time.", OccurredTime = DateTime.Now,
                        OperatorName = typeof(App).Name, LogType = LogType.Information
                };
            logs.Add(log);
            //[Local account creation] explains how to create these four accounts.
            //And how to navigate use logon script
            //CoreApplication.Exit();
        }
        else
        {
            log = new Log()
                {
                        Message = "this execution has run on this device more than twice.",
                        OccurredTime = DateTime.Now, OperatorName = typeof(App).Name,
                        LogType = LogType.Information
                };
            logs.Add(log);
            //[Desktop UI control] explains how to check current user
            //if (UserName == "maintenanceOperator") navigate to MaintenanceWindow
            //if (UserName == "appOperator") quiet this app. This account has specific automatic
            //run application when this account sign in.
            //if (UserName == "appUser") quiet this app. This account has specific automatic
            //run application when this account sign in.
        }
        log = new Log()
                {
                        Message = "checkking app files is complete.", OccurredTime = DateTime.Now,
                        OperatorName = typeof(App).Name, LogType = LogType.Information
                };
        logs.Add(log);
        dataAccessLayer.AppendWriteLogs(logs);
    }
}

Go next step [part 2] >>

or [Local account creation] >>

, [Desktop UI controlling] >>

, [Launch correct app by specific account] >>

About takao

I'm Microsoft MVP since June 2010.