AIR 2.0/ Flash Player/ Flex/ Flex 3

Capturando erros no seu aplicativo RIA no FP 10.1 e AIR 2.0

É tão bom quando você tem alguns minutos livres durante a semana para escrever alguma coisa no blog, que ultimamente tem sido tão deixado de lado!
Uma das grandes novidades do Flash Player 10.1 é a possibilidade de capturar todos os erros gerados pela sua aplicação RIA.
Comumente, desenvolvedores e inclusive nós, tinhamos o hábito de capturar os erros apenas comuns em uma aplicação, por exemplo: IOError, Load Errors, Event Erros, Converter Errors, porém querendo ou não acaba escapolindo do nosso controle uns errinhos como 1009,1056,2048 etc. Esses erros é de tirar o fôlego quando se trata de experiência do usuário, e principalmente quando se tem vários deles.

Infelizmente, isso já era para estar pronto desde a versão 9. Como não tinha, faziamos isso como comentei acima. O que, torna uma tarefa repetitiva e acaba virando um saco fazer sempre aquilo, embora você tente ao máximo re-utilizar seu código.

Contudo, para a grande saúde mental de desenvolvedores, a Adobe decidiu criar esse tipo de captura, dando ao desenvolvedor a oportunidade de verificar quais erros estavam ou estão sendo gerados tanto em backgrounds não mostrados no Stacker ou mostrados.

Nem tudo é um mar de rosas, esse tipo de captura de evento só funciona se seu navegador estiver com o Flash Player do tipo debug, inclusive acaba ficando disponivel apenas para usuarios desenvolvedores, impossibilitando assim você de logar automaticamente um erro e captura-lo e adiciona-lo a uma base de análise, que é comumente feito em sistemas enterprise.

Como era feito a captura de erros até então no Flash Player 9 e 10:

Geralmente como nossos requisitos sempre são simples, nada tão complexo, preferimos usar não a classe padrão de Log de erro do SDK do Flex, por que é além do que agente precisa, e como também existem outras ferramentas e frameworks no mercado para log de erros.

A classe LogManager ela adiciona os erros a um arrayCollection:

package com.igorcosta.debug
{
	import mx.collections.ArrayCollection;
 
	public class LogManager
	{
		[Bindable]private static var _arrError:ArrayCollection = new ArrayCollection();
 
 
		public static function get errors():ArrayCollection
		{
			return _arrError;
		}
		public function LogManager()
		{
 
		}
 
		public static function addError(error:LogError):void
		{
				_arrError.addItem(error);
		}
 
	}
}

E a classe que agente costuma chamar de LogError, nada mais é que um VO/DTO, etc:

package com.igorcosta.debug
{
 
	public class LogError
	{
		public function LogError()
		{
		}
		public var stack:String;
		public var name:String;
		public var ID:String;
		public var message:String;
	}
}

Ai para usarmos em um simples teste de erro, veja o aplicativo que fizemos para esse post. Acho que vai ajudar vocês a melhor enxergar como é penoso o trabalho de capturar os eventos.

< ?xml version="1.0" encoding="utf-8"?>
<application xmlns="http://www.adobe.com/2006/mxml" layout="vertical">
 
 
	<script>
		< ![CDATA[
			import mx.controls.Label;
			import com.igorcosta.debug.LogManager;
			import mx.utils.ObjectUtil;
			import com.igorcosta.debug.LogError;
 
 
 
			public var err:LogError;
 
			public function provocarErro(tipo:uint):void
			{
				switch(tipo){
 
						case 1:
 
							try{
								throw new IOError("I/O Error, de leitura ou escrita");
							}catch(erro:IOError){
									err = new LogError();
									err.stack = erro.getStackTrace();
									err.message = erro.message;
									err.ID = String(erro.errorID);
									err.name = erro.name;
									LogManager.addError(err);
							}
							break;
					   case 2:
					   		try{
					   			var temp:Label;
					   			temp.text = 'test';
					   		}catch(erro:Error){
					   				err = new LogError();
					   				err.stack = erro.getStackTrace();
									err.message = erro.message;
									err.ID = String(erro.errorID);
									err.name = erro.name;
									LogManager.addError(err);
 
					   		}
					   break;
					   case 3:
					   		try{
					   				stackTest();
					   		}catch(erro:Error){
					   				err = new LogError();
					   				err.stack = erro.getStackTrace();
									err.message = erro.message;
									err.ID = String(erro.errorID);
									err.name = erro.name;
									LogManager.addError(err);
 
					   		}
				}
			}
			private function stackTest():void
			{
					stackTest();//loop de funcao da um erro de StackOverflow
			}
		]]>
	</script>
 
 
	<hbox width="100%">
		<button label="Provocar erro 1009" click="provocarErro(2)"/>
		<button label="Provocar erro IO" click=" provocarErro(1)"/>
		<button label="Provocar erro Stack Overflow" click=" provocarErro(3)"/>
	</hbox>
	<datagrid dataProvider="{LogManager.errors}" x="103" y="160" width="743" height="308">
		<columns>
			<datagridcolumn headerText="Nome do Erro" dataField="stack"/>
			<datagridcolumn headerText="Nome do Erro" dataField="name"/>
			<datagridcolumn headerText="Mensagem de erro" dataField="message"/>
			<datagridcolumn headerText="ID do erro" dataField="ID"/>
		</columns>
	</datagrid>
 
</application>

Capturando erros gerais ou “Global Error handler” no Flash Player 10.1 e AIR 2.0:

Agora usando o mesmo aplicativo, podemos capturar qualquer tipo de erro gerado pelo Flash Player, ou mau uso do código. Um detalhe é que o novo recurso do Flash Player o Uncaught Error e Uncaught Error Event, são passíveis de receber qualquer erro ocorrido no swf compilado. Veja o exemplo abaixo:

< ?xml version="1.0" encoding="utf-8"?>
<mx :Application xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="completou()" layout="vertical">
 
    </mx><mx :Script>
        < ![CDATA[
        	import mx.controls.Label;
        	import com.igorcosta.debug.LogError;
        	import com.igorcosta.debug.LogManager;
            private function completou():void
            {
                loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, capturarErros);
            }
 
            private function capturarErros(e:UncaughtErrorEvent):void
            {
 
	        	if(e.error is Error){
 
	        		Error(e.error).getStackTrace();
	            	LogManager.addError(e.error as Error);
	         	}
	         	if(e.error is ErrorEvent){
	         		LogManager.addErrorEvent(e.error as ErrorEvent);
	         	}
 
            }
 
             private function identifica(e:MouseEvent):void
            {
 
                var minhaVar:Label;
                try
                {
                   minhaVar.text = " Ola Mundo" ;
                }
                catch (e:Error)
                {
                  // capturou o erro
                  minhaVar as Boolean;
                  trace(minhaVar.text);
                }
            }
        ]]>
    </mx>
     <mx :HBox width="100%" >
     <mx :Button label="Causar erro de  acesso indefinido" click="identifica(event);"/>
    </mx>
 
 
 
 
	<mx :DataGrid width="100%" dataProvider="{LogManager.errors}" x="29" y="182">
		</mx><mx :columns>
			<mx :DataGridColumn headerText="ID do Erro" dataField="errorID"/>
			<mx :DataGridColumn headerText="Nome do erro" dataField="name"/>
			<mx :DataGridColumn headerText="Mensagem de erro" dataField="message"/>
		</mx>

Lembrando que para você usar em seu projeto esse recurso do UncaughtError e UncaughtErrorEvent, você precisa ter o playerglobal.swc do Flash player 10.1, tanto para o Flash Player quanto para o AIR 2.0.

Os códigos fontes de ambos os aplicativos vocês podem baixar diretamente aqui.