<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>tygloBee</title>
	<atom:link href="http://www.tyglobee.cz/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.tyglobee.cz</link>
	<description>a place where a bee can sit on a hungry tiger</description>
	<lastBuildDate>Sat, 06 Dec 2008 22:25:07 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Logování ve Flexu II.</title>
		<link>http://www.tyglobee.cz/?p=21</link>
		<comments>http://www.tyglobee.cz/?p=21#comments</comments>
		<pubDate>Sat, 06 Dec 2008 14:30:30 +0000</pubDate>
		<dc:creator>tygl</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[AS3]]></category>
		<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://www.tyglobee.cz/?p=21</guid>
		<description><![CDATA[Minule (Logovani ve flexu) byla popsána tvorba a princip logovacího API Flexu. Dnes navážu pokračováním v tomto tématu, konkrétně půjde o vytvoření vlastního Log Targetu. Vlastní Log Target umožňuje přizpůsobení výstupu z Logerru k obrazu svému, což je dnešním cílem.

Než bude ukázána praktická část vytvoření a práce s vlastním Log Targetem, bylo by dobré popsat [...]]]></description>
			<content:encoded><![CDATA[<p>Minule (<a href="http://www.tyglobee.cz/?p=9">Logovani ve flexu</a>) byla popsána tvorba a princip logovacího API Flexu. Dnes navážu pokračováním v tomto tématu, konkrétně půjde o vytvoření vlastního Log Targetu. Vlastní Log Target umožňuje přizpůsobení výstupu z Logerru k obrazu svému, což je dnešním cílem.</p>
<p><span id="more-21"></span></p>
<p>Než bude ukázána praktická část vytvoření a práce s vlastním Log Targetem, bylo by dobré popsat princip spoluprace mezi Loggerem a Log Targetem.</p>
<p>Zprávy, které odesíláme pomocí metod poskytovaných Loggerem (<em>debug(), info(), error(), &#8230;</em>), jsou &#8220;vysílány&#8221; jako Event událost, konkrétně LogEvent. Aby Log Target tyto zprávy mohl přijímat, musí nastavit na daném Loggeru listener na událost LogEvent.LOG. Nastavení listeneru na tuto událost probíhá automaticky a odchycená událost je předána do metody <em>logEvent( event:LogEvent )</em>, která přijatou událost zpracuje, zformátuje a odešle na výstup.</p>
<p>Máme tento kód:</p>
<pre lang="actionscript3">var logTarget:ILoggingTarget = new TraceTarget();
logTarget.includeLevel = true;
logTarget.includeDate = true;
// .....
logTarget.filters = ["my.class.foo.*"];

// samotna registrace Log Targetu do spravce loggeru
Log.addTarget( logTarget );</pre>
<p>Při zavolání <em>Log.addTarget()</em> dojde k registraci zadaného Log Targetu. Metoda <em>addTarget() </em>zjistí, jaké kategorie zpráv bude registrovaný Log Target přijímat. Správce Loggerů projde filtry (<em>logTarget.filters = ["mu.class.foo.*"]</em> ) právě registrovaného Log Targetu a porovnává je s registrem kategorií Loggerů. Pokud najde Logger, který poskytuje zprávy jež Log Target chce, zavolá Log Target a předá mu informaci o nalezeném Loggeru. Log Target na předaném loggeru nastaví výše zmíněný listener na událost LogEvent.LOG. Od této chvíle Log Target přijímá zprávy odesílané daným Loggerem.</p>
<h2>Vlastní Log Target</h2>
<p>Flex poskytuje tyto vestavěné Log Targety:</p>
<ul>
<li>TraceTarget &#8211; vhodný pro základní logování, jako výstup je použita trace() konzole.</li>
<li>MiniDebugTarget &#8211; umožnuje přesměrovat výstup do jiného SWF souboru, pomocí LocalConnection.</li>
<li>LineFormattedTarget &#8211; základní Log Target, který nikam neposílá výstup a je často používán jako &#8220;taťka&#8221; pro vlastní loggery.</li>
</ul>
<p><em>LineFormattedTarget</em> je základním stavebním kamenem při tvorbě vlastního Log Targetu. Poskytuje základní metody, potřebné pro logování událostí. Sám o sobě vychází z třídy <em>AbstractTarget</em>, která definuje základní metody pro správu a příjem událostí z Loggerů. Rozdíl mezi nimi je ten, že <em>LineFormattedTarget </em>definuje metodu, pro základní formtováný výstup, čímž nám práci ulehčí. Kdežto <em>AbstractTarget </em>žádný výstup nedefinuje a je nutné si výstup formátovat osobně.</p>
<p>Na samotném začátku, při vytváření vlastního Log Targetu, stojíme před rozhodnutím z jaké třídy vycházet. Chceme-li pouze využít možnosti ukládání zpráv do souboru, popř. odesílání pomocí LCDS tak doporučuji vycházet z třídy <em>LineFormattedTarget</em>, protože pak stačí implementovat metodu <em>internalLog()</em>, která provádí samotný formátovaný výstup a přesměrovat na libovolný výstup.</p>
<p>Pokud však máme nároky vyšší, např. chci mít vlastní vlastní výstupní formát (např. datum, čas, aj.) tak již doporučuji sáhnout po metodě <em>AbstractTarget</em>. Bylo by možné použít<em> </em>i <em>LineFormattedTarget</em>, ale bylo by nutné implementovat nejméně dvě metody, jednu navíc z mx_internal namespace. <em>LineFormattedTarget</em> přijme událost do metody <em>logEvent</em>, zformátuje a zavolá metodu <em>internalLog()</em>, která provede samotné odeslání na výstup.</p>
<h3>Ukázka použití <em>LineFormattedTarget</em></h3>
<h4>Zadání problému:</h4>
<p>Mějme AIR aplikaci a zprávy o jejím běhu chceme zaznamenávat do zadaného souboru.</p>
<h4>Řešení:</h4>
<p>Pro tento případ se hodí použití třídy <em>LineFormattedTarget</em>, protože nemáme žádné požadavky na formát zprávy a je tedy možné použít výchozí formátování.</p>
<p>Naše třída bude vypadat např. takto:</p>
<pre lang="actionscript3">package
{
    import flash.filesystem.File;
    import flash.filesystem.FileMode;
    import flash.filesystem.FileStream;

    import mx.core.mx_internal;
    import mx.logging.targets.LineFormattedTarget;

    use namespace mx_internal;

    public class CustomLogger extends LineFormattedTarget
    {
       private var _file:File;
       private var _fileStream:FileStream;

    	public function CustomLogger()
    	{
            super();

            // chceme logovat dotohoto souboru, musime jej tedy otevrit pro zapis
	    _file = new File( "C:\\flexLog\\log.txt" );
            _fileStream = new FileStream();
            _fileStream.open( _file, FileMode.APPEND);
    	}

    	override mx_internal function internalLog(message:String):void
    	{
            // prijatou zpravu zapisujeme do souboru
            _fileStream.writeMultiByte( message + "\n", 'iso-8859-1' );
    	}

    }
}</pre>
<p>Výstup v log souboru bude asi takovýto:</p>
<pre lang="txt">12/6/2008 13:58:37.293 [DEBUG] my.class.logger.Main Button click
12/6/2008 13:58:37.421 [DEBUG] my.class.logger.Main Button click
12/6/2008 13:58:47.852 [DEBUG] my.class.logger.Main Button click</pre>
<p>Tímto jsme vytvořili vlastní Log Target, který si ponechává všechny možnosti nastavení a zároveň se nemusíme starat o formátování zprávy.</p>
<h3>Ukázka použití <em>AbstractTarget</em></h3>
<h4>Problém:</h4>
<p>Mějme stejné zadání z předchozí ukázky, avšak tentokrát je požadavek na formát zprávy. Zprávu je nutné zapisovat ve formátu <em>&#8220;DATE|TIME|LEVEL|CATEGORY@MESSAGE</em>&#8220;, protože log zprávy budou následně zpracovány jiným softwarem. Zároveň je nutné, aby byl vytvořen jedinečný soubor pro každé spuštění aplikace.</p>
<h4>Řešení:</h4>
<p>V tomto případě bude lepší jako základ použít třídu <em>AbstractTarget</em>, protože máme daný přesný formát zprávy a zároveň je nutné implementovat i vlastní metodu prozápis.</p>
<p>Třída bude vypadat např. takto:</p>
<pre lang="actionscript3">package
{
    import flash.filesystem.File;
    import flash.filesystem.FileMode;
    import flash.filesystem.FileStream;

    import mx.logging.AbstractTarget;
    import mx.logging.ILogger;
    import mx.logging.LogEvent;

    public class CustomLogger2 extends AbstractTarget
    {
       private var _file:File;
       private var _fileStream:FileStream;

    	public function CustomLogger2()
    	{
            super();

	    _file = new File( "C:\\flexLog\\log.txt" );
            _fileStream = new FileStream();
            _fileStream.open( _file, FileMode.APPEND);
    	}

        /**
         * metoda, ktera zpracovava prijate LogEvent udalosti
         */
    	override public function logEvent(event:LogEvent):void
    	{
    	    var date:Date = new Date();
    	    var message:String = "";

    	    // vlozime datum
    	    message += Number(date.getMonth() + 1).toString() + "." +
                       date.getDate().toString() + "." +
                       date.getFullYear().toString();

            // separator
            message += "|";

            // vlozime cas
            message += padTime(date.getHours()) + ":" +
                        padTime(date.getMinutes()) + ":" +
                        padTime(date.getSeconds()) + "." +
                        padTime(date.getMilliseconds(), true);
            //separator
            message += "|";   

            // vlozime uroven
            message += LogEvent.getLevelString( event.level );

            // separator
            message += "|";

            // vlozime kategorii loggeru, ktery poslal zpravu
            message += ILogger( event.target ).category;

            // separator
            message += "@";

            // vlozime obsah prijate zpravy
            message += event.message;

            // zapiseme zformatovanou zpravu do souboru
            log( message );
    	}

        /**
         * metoda prevzata z LineFormattedTarget, upravuje zobrazeni vterin
         */
        private function padTime(num:Number, millis:Boolean = false):String
        {
            if (millis)
            {
                if (num &lt; 10)
                    return "00" + num.toString();
                else if (num &lt; 100)
                    return "0" + num.toString();
                else
                    return num.toString();
            }
            else
            {
                return num &gt; 9 ? num.toString() : "0" + num.toString();
            }
        }

        /**
         * metoda zajisti vytvoreni jedinecneho jmena souboru
         * (pro jednoduchost neresi jakekoli konflikty, ktere by mohly
         * vzniknout, pokud by se aplikace spustila 2x v ten samy cas)
         */
        private static function _createLogName():String
        {
            var date:Date = new Date();

            return 'log_' + date.getTime() + '.log';
        }

        /**
         * metoda zapisuje zpravu do log souboru
         */
        protected function log( message:String ):void
        {
            _fileStream.writeMultiByte( message + "\n", "iso-8859-1" );
        }
    }
}</pre>
<p>Výstup v log souboru bude vypadat asi takto:</p>
<pre lang="text">12.6.2008|14:50:51.069|DEBUG|my.class.logger.Main@Button click
12.6.2008|14:50:51.359|DEBUG|my.class.logger.Main@Button click</pre>
<p>Vytvořili jsme tedy Log Target, ktery zaznamenavá zprávy dle zadání.</p>
<h2>Závěr</h2>
<p>Možností jak logovat je spousta, snažil jsem se (snad úspěšně) popsat jak využít kvalitního logovacího API, které poskutuje Flex. Log Targety nejsou omezené pouze na zápis do souboru, lze taktéž data rozesílat pomocí LCDS Messaging protokolů, popř. pomocí DataServices zapisovat do databáze. Možností je spousta a je těžké je všechny obsáhnout, ale i tak doufám, že jsem poskytl základní návod, jak správně logovat.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tyglobee.cz/?feed=rss2&amp;p=21</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Logování ve Flexu</title>
		<link>http://www.tyglobee.cz/?p=9</link>
		<comments>http://www.tyglobee.cz/?p=9#comments</comments>
		<pubDate>Mon, 01 Dec 2008 12:30:37 +0000</pubDate>
		<dc:creator>tygl</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[AS3]]></category>
		<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://www.tyglobee.cz/?p=9</guid>
		<description><![CDATA[Osobně považuji logování v aplikaci za jednu z nejdůležitějších funkcí. Logování jednotlivých akcí zpřehlední jednoduché &#8220;debugování&#8221;, popř. dokáže odhalit špatnou posloupnost akcí. Ve flashi, kde je asynchronní volání na denním pořádku se to může stát hned.

Dříve jsem si na logování napsal vlastní třídu, jednalo se o klasický singleton, který měl pár metod, které byly převážně [...]]]></description>
			<content:encoded><![CDATA[<p>Osobně považuji logování v aplikaci za jednu z nejdůležitějších funkcí. Logování jednotlivých akcí zpřehlední jednoduché &#8220;debugování&#8221;, popř. dokáže odhalit špatnou posloupnost akcí. Ve flashi, kde je asynchronní volání na denním pořádku se to může stát hned.</p>
<p><span id="more-9"></span></p>
<p>Dříve jsem si na logování napsal vlastní třídu, jednalo se o klasický singleton, který měl pár metod, které byly převážně statické. Stěžejní metodou byla metoda &#8220;log( msg:String, level:LoggerLevelEvent )&#8221;. Z popisu je jasné, že se předávaly dva parametry. Prvním byl text zprávy, druhým úroveň, která říkala, zda jde o zprávu debug, info, error, aj. Výstup byl prováděn na klasický trace output nebo do souboru, popř. obojí. Taktéž bylo možné zprávy filtrovat, protože jsem si zavedl konvenci, že na začátku každé zprávy byl název třídy, která zprávu posílala.</p>
<p>Vše fungovalo krásně, až do chvíle kdy jsem přišel na to, že jsem vynalezl kolo. Po pozdějším zjištění, hodně šišaté kolo. Místo, abych se nejdříve koukl do manuálu jsem si za par minutách napsal něco, co je už napsáno bylo. Řeč je o balíčku &#8220;mx.logging.*&#8221;. Jo, objevil jsem ameriku.</p>
<h2>mx.logging.*</h2>
<p>Nebudu zde citovat manuál balíčku <a href="http://livedocs.adobe.com/flex/3/langref/mx/logging/package-detail.html">mx.logging.*</a>. Zároveň také neřeknu nic nového, co by nebylo popsáno v manuálu, konkrétně kapitola: <a href="http://livedocs.adobe.com/flex/3/html/help.html?content=logging_09.html">Using the logging API</a>.</p>
<p>Stručně řečeno. Logování se dělí na tři části: &#8220;Logger -&gt; Log Target -&gt; Log Destination&#8221;. Flex jako takový logovací API nevyužívá, vyjímku tvoří pouze třídy: mx.rpc.*, mx.messaging.*, mx.data.* , které pomocí tohoto API zasílají informace o své činnosti.</p>
<h3><strong>Logger</strong></h3>
<p>Logger je v podstatě singleton, který poskytuje metody pro logování v danné kategorii. Veškeré Loggery jsou soustředěny a spravovány jednou třídou, konkrétně jde o třídu <a href="http://livedocs.adobe.com/flex/3/langref/mx/logging/Log.html">mx.logging.Log</a>. Tato třída poskytuje rozhraní na jejich vytváření a taktéž poskytuje metody na registraci &#8220;Log targetů&#8221;.</p>
<p>Chci-li získat Logger, pro vlastní kategorii, tak to vypadá asi takto:</p>
<pre lang="actionscript3">// definice balíčku a třídy my.class.foo.Bar
// ....
private var _log:ILogger = Log.getLogger('myCategory');
//....</pre>
<p><em>Log.getLogger(&#8216;myCategory&#8217;) </em>provede vytvoření zadané kategorie <em>myCategory</em>. Jako název lze volit libovolný textový řetězec, ale je dobré držet nějaký standard. Je doporučeno kategorii zadávat jako plný název třídy, napr.: my.class.foo.Bar. Na základě názvu kategorie můžeme následně logované zprávy filtrovat.</p>
<p>Mám li vytvořený logger, mohu začít zasílat zprávy, např. takto:</p>
<pre lang="actionscript3">// definice balíčku a třídy
// ....
private var _log:ILogger = Log.getLogger('my.class.foo.Bar');

public function Bar():void
{
  _log.debug('In constructor.');
  initClass();
}

private function initClass():void
{
  _log.info('InitClass');
}

private function doLogEvent( eventName:String ):void
{
  _log.log(LogEventLevel.DEBUG, "some info from event {0}", eventName );
}

private function doError( errorMsg:String, partName:String ):void
{
   if( Log.isError() ) {
     _log.error("Oou, we have a problem. Message: '{0}' from part: '{1}' ", errorMsg, partName );
   }
}
//....</pre>
<p>Jak je vidět, Logger poskytuje 5 základních metod a jednu obecnou metodu log(), která poskytuje možnost logovat zprávy i na vlastní úrovni.</p>
<ul>
<li>info( message:String, &#8230;rest ) &#8211; odpovídá zprávě na úrovni  LogEventLevel.INFO</li>
<li>debug( message:String, &#8230;rest ) &#8211; odpovídá zprávě na úrovni  LogEventLevel.DEBUG</li>
<li>warn( message:String, &#8230;rest ) &#8211; odpovídá zprávě na úrovni  LogEventLevel.WARN</li>
<li>error( message:String, &#8230;rest ) &#8211; odpovídá zprávě na úrovni  LogEventLevel.ERROR</li>
<li>fatal( message:String, &#8230;rest ) &#8211; odpovídá zprávě na úrovni  LogEventLevel.FATAL</li>
<li>log( level:Int, message:String, &#8230;rest )</li>
</ul>
<p>Všechny poskytované metody umožnují ve zprávách nahrazování parametrů, tj. pomocí syntaxe {x}, kde x je pořadové číslo dodatečného parametru (<em>&#8230;rest</em>).</p>
<p>V metodě <em>doError()</em> je použita další vlastnost třídy Log. Použitá konstrukce zajistí to, že zpráva bude do loggeru odeslána pouze za předpokladu, že je úrověn přijímaných zpráv vyžží než úroveň danné zprávy. K dispozici jsou metody na zjištění všech stavů: isInfo(), isDebug(), isError(), isFatal(), isWarn().</p>
<h3>Log Target</h3>
<p>Zjednodušeně a ve zkratce řečeno, je to v příjemce zpráv z loggerů. Z vestavěných Log Targetů je nejpoužívanější <a href="http://livedocs.adobe.com/flex/3/langref/mx/logging/targets/TraceTarget.html">TraceTarget</a>, ktery jako výstup používá stejnou konzoli jako příkaz trace(). Dále pak máme k dispozici MiniDebugTarget a LineFormattedTarget (nejlepší taťka pro psaní vlastních log targetů).</p>
<p>Každý Log Target umožnuje filtrovat přijímané zprávy pomocí vlastnosti <em>filters</em>, která jako hodnotu přijímá pole textových řetězců, které specifikují kategorie, které daný Log Target chce. Složitě řečeno, ale příklad vysvětlí.</p>
<pre lang="actionscript3">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
 creationComplete="init()"&gt;
 &lt;mx:Script&gt;
  &lt;![CDATA[
   //  .... imports ...

   private function init():void
   {
    var logTarget:ILoggingTarget = new TraceTarget();

    // chci přijímat pouze zprávy z těchto kategorií
    logTarget.filters = ["my.class.foo.*", "mx.rpc.*" ];

    // Vlastnost level určuje maximální úrověn přijímaných zpráv
    // Posloupnost úrovní je takováto (číslo vedle názvu vyjadřuje hodnotu úrovně):
    // LogEventLevel.FATAL (1000)
    // LogEventLevel.ERROR (8)
    // LogEventLevel.WARN (6)
    // LogEventLevel.INFO (4)
    // LogEventLevel.DEBUG (2)
    // LogEventLevel.ALL (0)
    //
    // Zprávy jsou přijímány od zadané úrovně nahoru, tj. pokud zadám:
    // logTarget.level = LogEventLevel.WARN
    // bude target přijímat pouze zprávy typu WARN, ERROR, FATAL
    //
    // V tomto případě chci přijímat všechny druhy zpráv
    logTarget.level = LogEventLevel.ALL;

    // jak budou jednotlivé položky odděleny, napr: datum : errorLevel : errorMessage
    logTarget.fieldSeparator = " : ";

    // ve zprávě chci zahrnout nazev ktergorie, ze které zpráva přišla
    logTarget.includeCategory = true;

    // ve zprávě chci vidět datum a čas vzniku zprávy
    logTarget.includeTime = true;
    logTarget.includeDate = true;

    // ve zprávě chci vidět úroveň zprávy
    logTarget.includeLevel = true;

    // zaregistrujeme logTarget do seznamu Loggerů
    Log.addTarget( logTarget );

    var myBar:Bar= new Bar();
    myBar.doLogEvent( "myClass" );
    myBar.doError( "myClass", "first" );
   }

  ]]&gt;
  &lt;/mx:Script&gt;
&lt;/mx:WindowedApplication&gt;</pre>
<p>Výstup do konzole bude např. takovýto:</p>
<pre lang="txt">12/1/2008 : [DEBUG] : my.class.foo.Bar : In constructor.
12/1/2008 : [INFO] : my.class.foo.Bar : InitClass
12/1/2008 : [DEBUG] : my.class.foo.Bar : Some info from event LogEvent
12/1/2008 : [ERROR] : my.class.foo.Bar : Oou, we have a problem. Message: 'LogEvent' from part: 'LogEventLevel'</pre>
<h3>Log Destination</h3>
<p>Poslední část je nejjednodušší. Pouze určuje, kam má Log Target odeslat formátovaný výstup přijaté zprávy. Může to být soubor, SharedObject, databáze, prostě cokoli. Toto je již v režii daného Log Targetu.</p>
<h3>Závěrem</h3>
<p>Nepopsal jsem zde úplně všechny možnosti logovacího API, ale jako základ by to mohlo stačit. Největší výhodu tohoto přístupu jsem si však nechal na později, konkrétně jde o vytvoření vlastního Log Targetu. Doufám, že popis byl srozumitelný a snad se to bude někomu hodit.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tyglobee.cz/?feed=rss2&amp;p=9</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
