Показаны сообщения с ярлыком quick start. Показать все сообщения
Показаны сообщения с ярлыком quick start. Показать все сообщения

воскресенье, 25 апреля 2010 г.

Введение в Log4php, часть 2. Использование

Итак, в первой части мы подключили к проекту log4php, сконфигурировали его. А что дальше?

суббота, 24 апреля 2010 г.

Введение в Log4php, часть 1. Конфигурация

Как известно, писать логи хорошо и полезно. Данная статье посвящена одному из самых мощных логгеров для PHP — log4php.
Log4php относится к тому же семейству, что и любимый мной log4net, так что многие понятия повторяются. И, кстати, у log4php имеется достаточно хорошая документация. Настолько хорошая, что в этой моей статье, в общем-то, нет ровно ничего оригинального.

четверг, 16 октября 2008 г.

Знакомство с Android. Часть 1: Простое приложение для Android

Недавно заинтересовала меня платформа Android. Как-то много говорят о нем в последнее время, да и вообще хотелось узнать, такая же ли там ужасная Java, как в мидлетах. Так что потратила я некоторое время на копание в нем, написала простое приложение, и сейчас вот буду делиться опытом.

UPDATE

Серия статей по игре Life обновлена 03.11.2010. Исправлены ошибки и проведена адаптация под Android версии 2.2. Всем спасибо за замечания и дополнения!

Постановка задачи

Первым нашим приложением для Android будет реализация всем известной игры Life. Местом дейтвия будет прямоугольное клеточное поле, размеры которого запрашиваются у пользователя. Также у пользователя запрашивается начальное количество клеток. Первое поколение расставляется по карте случайным образом. Последующие поколения получаются по следующим правилам:
  • Если у живой клетки меньше двух или больше трёх соседей, то она погибает.
  • Если у пустой клетки ровно три соседки, она оживает.
Все входные параметры должны проверяться на правильность: столбцов должно быть не меньше 5 и не больше 25, строк должно быть не меньше 5 и не больше 35, начальное количество клеток должно быть не больше, чем ячеек на поле. Для реализации поля будет использован класс GridView.
Для разработки была использована среда Eclipse и Android plugin для неё.
Статья будет из четырех частей:
Итак, начнём.

В этой части

Мы создадим проект, рассмотрим его структуру и напишем простое приложение, состоящее из одной формы. На форме будет интерфейс для ввода данных и кнопка Run.

Создание и обзор проекта

На установке Android SDK и плагина для Eclipse останавливаться не будем, т.к. это достаточно подробно описано в официальном мануале. Создаем в Eclipse новый Android Project:
Создание нового проекта под Android
После нажатия на кнопку Finish создастся новый проект с такой структурой файлов:
Структура проекта
Рассмотрим эту структуру внимательнее.

/res/drawable-dpi

Сюда помещаются все графические файлы, используемые в приложении, для разных разрешений экрана. На данный момент там есть только файл icon.png - главная иконка приложения.

/res/layout

В эту папку помещаются файлы, в которых в формате XML описывается внешний вид форм, расположение контролов и т.д. (как dfm-ки в Дельфи). Плагин даже создал разметку для нашей единственной формы и назвал её main.xml. Позже мы рассмотрим ее подробнее.

/res/values

В этой папке хранятся общие константы для всего приложения, как то: текст, используемый элементами управления, цвета, стили и т.д.. Например, если мы хотим вывести "Hello World" в TextView, можно это сделать явно в разметке, как мы всю жизнь делали в тех же dfm-ках или aspx; либо создать в strings.xml константу hello со значением "Hello World", после чего пойти обратно в разметку и в атрибутах этого TextView прописать android:text="@string/hello".

/gen/R.java

Это такой специальный сгенерированный класс, посредством которого осуществляется доступ к ресурсам приложения (т.е. ко всему тому, что есть в папке res). Например, R.string.hello возвращает константу с именем hello из strings.xml.

StartActivity.java

Это нам плагин сгенерировал класс для главной (и пока что единственной) формы приложения. Там пока содержится единственный обработчик onCreate, и написано там только setContentView(R.layout.main);. С помощью этой строчки к данной форме привязывается разметка, описанная в файле /res/layout/main.xml

AndroidManifest.xml

В этом файле перечисляются общие свойства проекта (версия, package и прочее), а также все формы (Activities), входящие в проект.

Разметка формы (Layout)

Элементы управления в Android называются Views и наследуются от класса View или ViewGroup. Класс ViewGroup также унаследован от View, но его отличие в том, что в него могут быть вложены другие View или ViewGroup.
Иерархия View
Плагин создал простейшую разметку для нашей единственной формы (main.xml):

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
</LinearLayout>
Вначале задаётся Layout, т.е. правило, согласно которому элементы управления следуют друг за другом. LinearLayout значит, что они идут друг за другом сверху вниз (android:orientation="vertical"). Бывают и другие Layout-ы: TableLayout, с помощью которого можно выстроить контролы в таблицу; FrameLayout, который ставит контролы один на другой; и т.д.
Мы воспользуемся TableLayout
Сделаем вот такую разметку:

main.xml

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:stretchColumns="1"
    android:padding="10dip"
    >
    <TableRow android:paddingBottom="5dip">
        <TextView
            android:text="@string/columns_title"
            android:paddingRight="10dip"
            android:gravity="right"
            android:textStyle="bold"
        />
        <EditText
            android:id="@+id/columns_count"
            android:text="25"
            android:inputType="number"
        />
    </TableRow>
    <TableRow android:paddingBottom="5dip">
        <TextView
            android:text="@string/rows_title"
            android:paddingRight="10dip"
            android:gravity="right"
            android:textStyle="bold"
        />
        <EditText
            android:id="@+id/rows_count"
            android:text="35"
            android:inputType="number"
        />
    </TableRow>
    <TableRow android:paddingBottom="5dip">
        <TextView
            android:text="@string/cells_title"
            android:paddingRight="10dip"
            android:gravity="right"
            android:textStyle="bold"
        />
        <EditText
            android:id="@+id/cells_count"
            android:text="100"
            android:inputType="number"
        />
    </TableRow>
    <TableRow>
        <Button
            android:id="@+id/run"
            android:text="@string/run_title"
            android:textStyle="bold"
            android:layout_span="2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
        />
    </TableRow>
</TableLayout>
В файл res/values/strings.xml при этом нужно добавить следующие строки:

strings.xml

<string name="run_title">Run!</string>
<string name="columns_title">Columns:</string>
<string name="rows_title">Rows:</string>
<string name="cells_title">Cells:</string>
Форма при этом будет выглядеть так:
StartActivity
Рассмотрим некоторые атрибуты, использованные в разметке

android:id

Идентификатор элемента. Если он указан, то в дальнейшем его можно найти на форме с помощью метода findViewById(id). Для контролов, которых мы не планируем в дальнейшем трогать (например, для заголовков), можно это свойство и вовсе не указывать. Идентификаторы можно складывать в файл ids.xml, но вместо этого обычно применяется синтаксис @+id/View1. Это означает, что идентификатор View1 добавляется в константы прямо на ходу. В R.java соответствующие поля также добавляются автоматически.

android:layout_width и android:layout_heigth

Свойства layout_width и layout_heigth обозначают, какую часть родительского контрола будет занимать данный элемент управления: всю (fill_parent или match_parent, начиная с 2.2) или ровно столько, сколько требуется (wrap_content). Можно также задавать численные значения.

android:inputType

Это атрибут EditText. С его помощью можно устанавливать формат вводимого значения. Есть ряд предопределенных форматов (date, phone, etc). Значение number значит, что в это поле можно вводить только целые положительные числа.

android:gravity, android:layout_gravity

Устанавливает выравнивание в данном элементе управления. Отличие в том, что gravity задает выравнивание дочерних контролов, а layout_gravity задает выравнивание самого контрола.

Заключение

Итак, мы создали проект для Android, рассмотрели его структуру, составили разметку для нашей единственной формы.
Исходники примера

Знакомство с Android. Часть 2: Переходы между формами

Итак, продолжим. В этой части мы добавим в проект ещё одну форму и будем открывать её по нажатию кнопки Run. Также сделаем так, чтобы параметры, которые были введены в первой форме, передавались во вторую (они там ещё пригодятся). Однако, ничего страшного мы пока с ними делать не будем, а просто напишем "Введены такие-то числа"

Знакомство с Android. Часть 3: Использование диалогов

В этой части мы сделаем проверку вводимых параметров по следующим правилам:
  • Число столбцов должно быть не меньше 5 и не больше 25.
  • Число строк должно быть не меньше 5 и не больше 35.
  • Начальное количество клеток должно быть не больше, чем ячеек на поле.
Если какое-то из этих условий не выполняется, будем выводить соответствующее предупреждение
Кроме того, мы добавим кнопку Close, при нажатии на которую приложение будет закрываться, спрашивая вначале согласие пользователя.

Знакомство с Android. Часть 4: Использование GridView

Итак, в нашем приложении осталось всего ничего: реализовать собственно алгоритм игры Life и отобразить его в GridView. Этим-то мы сейчас и займёмся.

среда, 9 апреля 2008 г.

Использование log4net

log4net - логгер для .net-приложений, позволяющий выводить любые сообщения в файл, несколько файлов, в БД или еще куда-нибудь. Кроме самого пользовательского сообщения, может вывести подробную информацию (время, класс, метод, и т.д., где был вызван вывод данного сообщения).

Подключение

Web Application

  1. Добавить log4net.dll в References приложения
  2. Добавить в AssemblyInfo.cs строку
    [assembly: log4net.Config.XmlConfigurator(Watch = true)]
    

Web Site

Просто переписать log4net.dll в каталог Bin

Настройка

Логгер настраивается в web.Config. Вначале в раздел configSections следует добавить строчку:

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net">

Затем, нужно добавить раздел:

<log4net debug="true">
...
</log4net>

В этом разделе идет основная настройка логгера. В разделе могут быть потомки типа appender, logger и root. Назначение элемента logger пока что осталось для меня загадкой, так что рассмотрим остальные.

Appender

Для того, чтобы заставить log4net что-то куда-то писать, нужно определить Appender. Подходящее русское обозначение мне придумать не удалось, но суть в том, что он хранит настройки одного логгера. Типов appender-ов существует много (см. документацию), но мне довелось работать только с RollingFileAppender, который определяет логгер, пишущий в файл. Другие типы appender-ов позволяют писать в базу данных(AdoNetAppender), Windows EventLog (EventLogAppender) и т.д. Рассмотрим пример:

<appender name="ERRORFileAppender" type="log4net.Appender.RollingFileAppender">
  <lockingmodel type="log4net.Appender.FileAppender+MinimalLock"/>
  <file value="\Logs\errors.log" />
  <appendtofile value="true" />
  <rollingstyle value="Size" />
  <maxsizerollbackups value="10" />
  <maximumfilesize value="200MB" />
  <staticlogfilename value="true" />
  <filter> ... </filter>
  <layout> ... </layout>
</appender>

Назначение перечисленных Appender-а, в принципе, понятно. Следует отметить параметр lockingModel и его значение MinimalLock. Дело в том, что log4net во время работы приложения жестко лочит файл с логом, его нельзя ни открыть (разве что редактором Far-а), ни удалить. Поэтому, если очень хочется удалить лог web-приложения, нужно перезапускать IIS, что не есть хорошо. Данная настройка "разлочивает" лог, его свободно можно удалять и открывать хоть для записи.

Ключевыми настройками Appender-а являются Filter и Layout.

Filter

Данная настройка позволяет отфильтровывать сообщения по некоторому признаку. Для фильтра обязательно указывается тип. Существует несколько типов фильтров, можно также писать свои. Наиболее часто используемые фильтры - по типу сообщения (LevelRangeFilter и LevelMatchFilter) и по тексту сообщения (StringMatchFilter). Для начала, остановимся на типах (уровнях) сообщений. Сообщения в log4net делятся на несколько уровней:

  • ALL
  • DEBUG
  • INFO
  • WARN
  • ERROR
  • FATAL
  • OFF

Разработчик выбирает, какой тип сообщений в каком случае ему использовать. Логгер же можно настроить таким образом, чтобы, к примеру, ошибки выводились отдельно, а отладочные данные - отдельно. Для это и пишутся фильтры. Рассмотрим на примерах.

Фильтр, выбирающий только ошибочные и фатальные сообщения:

<filter type="log4net.Filter.LevelRangeFilter">
  <levelMin value="ERROR"/>
  <levelMax value="FATAL"/>
</filter>

Фильтр, выбирающий только отладочные сообщения

<filter type="log4net.Filter.LevelMatchFilter">
  <levelToMatch value="DEBUG"/>
  <acceptOnMatch value="true"/>
</filter>

Layout

В разделе Layout определяется формат вывода сообщений в файл. Как ранее было сказано, log4net, помимо самого сообщения, может выводить кучу полезной информации. Layout может выглядеть, например, таким образом:

<layout type="log4net.Layout.PatternLayout">
  <conversionPattern value="%-5p [%d] [%C.%M] %m%n"/>
</layout>

В conversionPattern указано, какие значения и в каком формате будут выводиться в лог. Выходной лог с таким Layout-ом получится примерно таким:

DEBUG [2008-04-08 17:45:14,662] [TableTemplates.GetTemplate] Is visible: [visible]
DEBUG [2008-04-08 17:45:14,662] [TableTemplates.GetTemplate] Report Footer (rows:1)
DEBUG [2008-04-08 17:45:14,662] [TableTemplates.GetTemplate] Number of cells in row [2]
INFO  [2008-04-08 17:45:14,663] [ClientDataObjects.get_ClientObjects] Client object found in session

Значения ключей conversionPattern:

  • %p — Тип события лога (DEBUG, ERROR и т.д.)
  • %d — Дата и время, когда логгирующая функция была вызвана. Можно задавать различные форматы вывода даты и времени. К примеру, %d{HH:mm:ss,SSS} отображает только время
  • %C — Имя класса, в котором была вызвана какая-либо функция лога
  • %M — Имя метода
  • %m — Собственно, сообщение в лог
  • %F — Имя файла
  • %l — Номер строки
  • %r — Количество миллисекунд, прошедших с начала работы программы
  • %t — Имя потока
  • %n — Переход на новую строку
  • %% — Символ "%"

Root

Написать Appender-ы недостаточно для того, чтобы log4net начал писать логи. Нужно еще зарегистрировать их в корне лога, вот таким вот образом:

<root>
  <level value="WARN" />
  <appender-ref ref="ERRORFileAppender" />
  <appender-ref ref="DEBUGFileAppender" />
</root>

level - уровень, сообщения ниже которого не выводятся ни в один лог. Приведенная запись значит, что в логи не будут выводиться сообщения типа DEBUG и INFO.

Использование

Я делаю так. Пишу класс:

using log4net;
using log4net.Config;
using System;

///
/// Logger - shell for log4net logger
///
public static class Logger
{
  private static readonly ILog log = LogManager.GetLogger(typeof(Logger));

  public static ILog Log
  {
    get { return log; }
  }

  public static void InitLogger()
  {
    XmlConfigurator.Configure();
  }
}

Потом в Global.asax в метод Application_Start добавляю строчку:

Logger.InitLogger();

И подключение лога в код готово. После этого в любом месте кода можно написать что-то вроде:

Logger.Log.Debug("Some message");
Интерфейс ILog представляет различные методы для вывода сообщений различных типов. Рассмотрим некоторые методы:
Функции Описание Пример
Info(String message)

Debug(String message)

Warn(String message)

Error(String message)

Fatal(String message)
Вывод в лог сообщения message
Logger.Log.Info("Sample log message");
InfoFormat(String format, params object[] args)

DebugFormat(String format, params object[] args)

WarnFormat(String format, params object[] args)

ErrorFormat(String format, params object[] args)

FatalFormat(String format, params object[] args)
Вывод в лог сообщения c параметрами. Аналогично выводу сообщения String.Format(format, args).
Logger.Log.DebugFormat("Key={0}, Value={1}", key, value);
Info(String message, Exception e)

Debug(String message, Exception e)

Warn(String message, Exception e)

Error(String message, Exception e)

Fatal(String message, Exception e)
Вывод в лог сообщения с исключением. В лог помещается целиком текст исключения и stack trace.
try
{
  a = b / c;
}
catch (Exception e)
{
  Logger.Log.Error("Exception catched while calculation.", e);
}