29 de mar. de 2009

Monitoração de domínio e gravação de thread dump automático com WLST

Outro dia me deparei com um questionamento no fórum de discussão sobre como conseguir retirar os thread dumps do Servidor de aplicações, Oracle Weblogic, em momento oportuno, ou seja, quando o ambiente estiver passando por um momento de contingência. A discussão do problema pode ser vista detalhadamente no fórum do javaranch no link: http://www.coderanch.com/t/427054/BEA-Weblogic/Issue-with-WeblogicServer

Devido a este problema decidi escrever um artigo mostrando como podemos utilizar a linguagem de scripts do Weblogic Server, Weblogic Scripting Tool(WLST), para fazer monitoramento de servidores. Um ponto importante nestes script é que ele permite inclusive que este monitoramente seja feito de forma independente do Admin Server, pois neste caso, o script mostra conexão direta com servidores gerenciados de um domínio. Para escrevê-lo estou utilizando WLST que por sua vez utiliza linguagem Jython e é padrão para configuração do Oracle Weblogic.

O script:

O script demonstrado aqui é bem simples e o que ele faz basicamente é:

1) Carregar informações de um arquivo de propriedades.

2) Tenta conectar com cada um dos servidores da lista de servidores configurada no arquivo de propriedades.

3) Verifica status do servidor e caso o servidor estiver com um número maior que o definido de threads com delay na resposta gera um thread dump do servidor para posterior análise.

Abaixo segue o código do script comentado e logo em seguida um exemplo de arquivo de propriedades que pode ser utilizado como template.

from java.util  import Properties
from java.io  import FileInputStream
from java.io  import File

#============DEFINICAO DE FUNCOES============
#funcao que carrega dados de arquivo de propriedades
def carregaArquivoPropriedades(nomeArquivo) :
    print 'carregando propriedades do arquivo: ' + nomeArquivo
    #arquivo de propriedades a ser carregado
    localizacaoArquivoPropriedadesConfiguracao = nomeArquivo    
    myProps = Properties()
    #carrega arquivo de propriedades
    myProps.load(FileInputStream(File(localizacaoArquivoPropriedadesConfiguracao)))
    return myProps

#funcao que retorna lista de todos os servidores configurados para este domínio.
def getServidoresDominio():
    print 'executando funcao getServidoresDominio']
    domainConfig()
    servidores = cmo.getServers()
    return servidores

#funcao que pega lista de servidores como parametro e verifica o status de cada um deles.
def mostraStatusServidores(servidores): 
    print '=======================STATUS dos servidores do domínio==============='
    domainRuntime()
    for servidor in servidores:
        try:
            cd('/ServerRuntimes/' + servidor.getName())
            #ls()
            print servidor.getName() + ': ' + get('State')
        except WLSTException,e:
            servidoresNaoAcessiveis.append(servidor)
    servidoresAlerta = []
    #testa novamente servidores que não estava acessíveis para ter certeza
    for servidor in servidoresNaoAcessiveis : 
        try:
            cd('/ServerRuntimes/' + servidor.getName())
            #ls()
            print servidor.getName() + ': ' + get('State')
        except WLSTException,e:
            servidoresAlerta.append(servidor)
    if len(servidoresAlerta) > 0 :
        print 'ALERTA == ALERTA == ALERTA == ALERTA == ALERTA == ALERTA =='
        print 'Os seguintes servidores estão inacessíveis para monitoração, favor checar!'
        for servidor in servidoresAlerta :
            print servidor.getName()
            
#faz checagem de memória nos servidores do domínio especificado.
def listaConfiguracoesMemoriaServidoresDomino():
    servidoresComBaixoHeapMemoria = []
    for servidor in servidores:
        try:
            cd("domainRuntime:/ServerRuntimes/" + servidor.getName() + "/JVMRuntime/" +servidor.getName())
            heapSizeMax = cmo.getHeapSizeMax()/1048576
            heapMemoriaLivre = cmo.getHeapFreeCurrent()/1048576
            heapMemoriaLivrePercentagem = cmo.getHeapFreePercent()
            #adiciona na lista de servidores com pouca memoria se servidor tiver menos de 2% de memória livre
            if heapMemoriaLivrePercentagem < 2 :
                servidoresComBaixoHeapMemoria.append(servidor)
            #memoriaMB = memoria/1048576 #transforma os bytes em MB para mostrar
            print '\n================================================================='
            print "O servidor " + servidor.getName() + " esta com :"
            print 'Memoria total alocada(MB): ' + str(heapSizeMax)
            print 'Memoria total disponivel(MB): ' + str(heapMemoriaLivre)
            print 'Memoria livre(%): ' + str(heapMemoriaLivrePercentagem)
        except WLSTException,e:
            print 'AVISO: O servidor ' + servidor.getName() + ' nao esta acessivel atraves do admin server'
    #faz novo teste de heap de memória e caso continuem com pouca memória disponível, mostra ALERTA para observação do servidor.
    for servidor in servidoresComBaixoHeapMemoria :
        try:
            cd("domainRuntime:/ServerRuntimes/" + servidor.getName() + "/JVMRuntime/" +servidor.getName())
        except WLSTException,e:
            print 'AVISO: O servidor ' + servidor.getName() + ' nao esta acessivel atraves do admin server'
            heapMemoriaLivrePercentagem = cmo.getHeapFreePercent()
            #adiciona na lista de servidores com pouca memoria se servidor tiver menos de 2% de memória livre
            if heapMemoriaLivrePercentagem < 2 :
                print 'ALERTA == ALERTA == ALERTA == ALERTA == ALE RTA == ALERTA =='
                print 'O servidor ' + servidor.getName() + ' está com heap de memória < que 2% e deve ser observado!'
#faz checagem de threads dos servidores do domínio
def checaThreadsServidoresDominio() :
    servidoresComThreadsProblematicas = []
    for servidor in servidores :
        try:
            cd("domainRuntime:/ServerRuntimes/" + servidor.getName() + "/ServerChannelRuntimes/DefaultSecure[https]")
            numeroConexoes = cmo.getConnectionsCount()
            print '==============================================='
            print 'Dados do servidor ' + servidor.getName() + ': '
            print 'Conexoes https: ' + str(numeroConexoes)
            cd('domainRuntime:/ServerRuntimes/' + servidor.getName() + '/ExecuteQueueRuntimes/weblogic.socket.Muxer')
            fila = cmo.getPendingRequestCurrentCount()
            print 'Requisicoes de usuarios pendentes: ' + str(fila)
            cd('domainRuntime:/ServerRuntimes/' + servidor.getName() + '/ThreadPoolRuntime/ThreadPoolRuntime')
            hoggingThread = cmo.getHoggingThreadCount()
            print 'Quantidade de threads com status hogging: ' + str(hoggingThread)
            print '===============================================\n'
        except WLSTException,e:
           print 'Erro servidor não acessivel para ServerRuntimes ==>> ' + servidor.getName()

#faz health check nos pools de conexao do ambiente.
def checaPoolsConexoes() :
    domainConfig()
    #recupera lista de pools de conexões configuradas no domínio.
    connectionPools = cmo.getJDBCSystemResources()
    for pool in connectionPools : 
        print pool.getName()
        cd('domainConfig:/JDBCSystemResources/' +pool.getName()+ '/JDBCResource/' +pool.getName()+ '/JDBCConnectionPoolParams/' + pool.getName())
        print '==============================================='
        print 'Dados do pool: ' + pool.getName()
        capacidadeInicialPool = cmo.getInitialCapacity()
        capacidadeMaximaPool = cmo.getMaxCapacity()
        print 'Capacidade maxima do pool: ' + str(capacidadeMaximaPool)
        cd('domainConfig:/JDBCSystemResources/' + pool.getName())
        targetServers = cmo.getTargets()
        print 'targets do pool'
        for targetServer in targetServers :
            print targetServer.getName()
#=================FIM DEFINICAO DE FUNCOES======================
propriedades = carregaArquivoPropriedades('config.properties')
username = propriedades.get('username')
password = propriedades.get('password')
url = propriedades.get('url')
connect(username, password, url)
#lista para armazenar servidores não acessíveis através do admin server.
servidoresNaoAcessiveis = []
servidores = getServidoresDominio()
mostraStatusServidores(servidores)
listaConfiguracoesMemoriaServidoresDomino()
checaThreadsServidoresDominio()
checaPoolsConexoes()
disconnect()
exit()


E o arquivo de propriedades de exemplo:
#este arquivo de propriedades é utilizado para configurar os   
#servidores em um ambiente. Todas as chaves devem ter o formato  
#do nome utilizando sempre _ (underscore) pois é o que define a   
#busca dos nomes dos elementos e separa durante a configuarção   
#no script criaInstancias.py  
USUARIO_ADMIN=user  
SENHA_ADMIN=pwd  
   
PORTA_HTTPS_SERVIDORES=443  
   
#parametro que configura com que quantidade de threads com delay o thread dump deve ser tirado para o servidor.  
PARAMETRO_THREAD_DUMP=10  
   
#Dados dos servidores a serem monitorados pelo script  
SERVIDOR_1=server1  
IP_SERVIDOR_1=xxxxxx  
  
SERVIDOR_2=server2  
IP_SERVIDOR_2=xxxxxxx  
   
SERVIDOR_3=server3  
IP_SERVIDOR_3=xxxxxx  
   
SERVIDOR_4=server4  
IP_SERVIDOR_4=xxxxxx  
   
# .... you may add as many servers as you want here...  


Para este script ficar realmente funcional eu programaria para que ele ficasse conectado com os servidores por um período definido em ciclos e que verificasse o status de cada um de tempos em tempos(3 em 3min por exemplo). E caso o servidor apresentasse algum problema considerável dispararia uma rotina que seria responsável por tirar thread dumps com intervalo de cerca de 20s entre um e outro por um período de 2 min. Os thread dumps retirados seriam de extrema utilidade para definir qual o real problema com o ambiente.

[]s

26 de mar. de 2009

Formatação de código-fonte para postagens no Blog

Fiquei algum tempo sem postar código fonte no blog pois como um blogueiro recente ainda não tinha conhecimento de como fazer para formatar o código fonte de uma maneira aceitável nos posts. 

Bem, como este é um blog técnico ficou impossível continuar dessa forma e portanto hoje resolvi pesquisar uma forma de fazer formatação de códigos fonte para postagens no blog. Pesquisando um pouco decidi primeiramente experimentar mais um produdo hospedado no Google code chamado SyntaxHighlighter http://code.google.com/p/syntaxhighlighter/  . A última versão(quei irei tratar neste artigo) migrou para http://alexgorbatchev.com/wiki/SyntaxHighlighter

Minha maior curiosidade é ver como uma linguagem como Jython, que uso muito no weblogic e tenho alguns posts aqui, vai ficar formatada imagino que java deve ficar bem bacana por ser mais comum.
Segue um passo-a-passo do que fiz para fazê-lo funcionar e alguns links de postagens deste blog já formatadas com este utilitário. 

O primeiro passo é baixar o pacote do projeto no link: http://alexgorbatchev.com/wiki/SyntaxHighlighter:Download
A última versão quando escrevo este é 2.0.296 .
O pacote contém um conjunto de javascript + css para formatação dos códigos.
Este conjunto deve ser disponibilizado na web para que possa ser acessado e essa foi minha primeira dificuldade, já estava pensando em fazer o upload para o ambiente que tenho contratado na locaweb(que por sinal é um excelente Hosting, não conheço melhor no Brasil) quando pesquisando a documentação do produto encontrei este link: http://alexgorbatchev.com/wiki/SyntaxHighlighter:Hosting
O criador do produto disponibiliza um repositório na web para acesso ao css e javascript e portanto vou testá-lo, se for o caso e eu sentir problemas de performance aí sim vou utilizar a Locaweb. Para utilizar o repositório disponibilizado nem havia necessidade de baixar o pacote!!!

O padrão para utilizar o hosting do autor, conforme documentação é:  http://alexgorbatchev.com/pub/sh/[VERSION]  e todas as versões disponíveis podem ser encontradas no link: http://alexgorbatchev.com/pub/sh/
Para utilizar o formatador o primeiro passo é declarar nas postagens desejadas o seguinte trecho de código que deve ser inserido no template de página no painel de administração do seu blog . No caso do blogger ir em Layout > Editar Html e colocar o javascript entre dentro da tag head do template, sugiro colocar imediatamente antes do fechamento da tag /head> depois salvar . (Eliminei tag de abertura html pois estava tendo problemas para mostrar!!! Alguém tem uma dica???): 

link type="text/css" rel="stylesheet" href="/styles/shCore.css">
link type="text/css" rel="stylesheet" href="/styles/shThemeDefault.css">
script type="text/javascript" src="/scripts/shCore.js">
script type="text/javascript" src="/scripts/shBrushJScript.js">
script type="text/javascript" src="/scripts/shBrushBash.js">
script type="text/javascript" src="/scripts/shBrushCpp.js">
script type="text/javascript">
syntaxhighlighter.all();</script>

Importante lembrar, e o autor do produto cita isso, que os caracteres de tag html e xml devem ser corretamente substituídos:

< por &lt;
> por &gt; (ok.. ok.. esse não é obrigatório mas é uma boa prática).
Outra coisa é que se for usar o repositório disponibilizado deve-se mudar as referências passando o caminho completo, ex: 

link type="text/css" rel="stylesheet" href="/styles/shCore.css">
Fica para versão 2.0.296: 
link type="text/css" rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/2.0.296/styles/shCore.css">
Lembrem-se que retirei a tag de abertura &lt 
e assim segue para todas as referências.

Feito isso deve-se usar tags pre de html para formatar os códigos desejados e definir o que o autor chama de Brush relacionando ao padrão de fontes que está sendo formatado (java, javascript, etc).
Ver lista completa em: http://alexgorbatchev.com/wiki/SyntaxHighlighter:Brushes
Exemplo formatação javascript: 

pre class="brush: js">alert("Hello world")/pre>
Um link em que já utilizo o recurso como referência: 
http://mmaiacupofcoffee.blogspot.com/2009/03/jme-implementacao-de-api-para.html
P.S - Para cada brush que você decidir utilizar tem um javascript diferente que deve ser carregado.

P.S2 - Implementei em todo o blog a formatação de código. Deu um trabalho considerável(umas 4 horas para revisar cerca de 30 posts, ainda bem que sou blogueiro mirim ainda!!!!) pois tive que desabilitar a quebra automática de linha em Configurações > Formatação > Converter quebras de linha tive que colocar não pois caso contrário a ferramenta de edição deste blogger colocava automáticamente quebras de linha(br) nos códigos!!!
[]s

24 de mar. de 2009

Appfuse - Utilizar tooltip do struts 2 causa um erro com Dojo

Recentemente um problema simples me tomou algumas horas de pesquisa e o problema, como usual, era simples de ser resolvido.
Utilizando Struts 2 do Appfuse para desenvolvimento de uma aplicação quando colocava um tooltip no formulário percebia um erro mostrado pelo firebug no firefox o tooltip era:


E o erro mostrado pelo firebug:
dojo is not defined:dojo.requ...);dojo.require("dojo.fx.html"); 

Fiz uma postagem na lista de discussão do appfuse em : http://www.nabble.com/Using-struts-2-tooltip-causes-error!-td22669446s2369.html
E a solução do problema foi bem simples e envolve 2 passos:
1) Mudar a extensão do mapeamento do struts 2 de .html que é o default do appfuse pois isso causa conflito com dojo. (Esse passo eu já havia feito no meu projeto).
2) Adicionar a tag s:head do struts ao head html da página.
O problema foi resolvido, no meu caso, só com a s:head adicionada. Bem simples e me tomou um tempo considerável.
[]s

23 de mar. de 2009

Ubuntu - Dicas de configuração de ambiente - Instalação Mysql, Maven e Efeitos Desktop

Este final de semana instalei o Ubuntu 8.10 no meu desktop para utilizar como ambiente de trabalho e desenvolvimento de software. Durante a instalação encontrei algumas dificuldades básicas que me tomaram algum tempo e por isso segue aqui algumas dicas e links de sites de como eu resolvi tais problemas para futura referência.

Instalação do Mysql, Mysql Admin Tools e Maven - A melhor forma de instalar o Mysql que encontrei foi utilizando a ferramenta Synaptic Package Manager(System > Administration > Synaptic Package Manager). Basta procurar por Mysql na busca da ferramenta, selecionar o que deseja instalar, e pronto, bem prático. Já para instalar o maven basta abrir um console e digitar sudo apt-get install maven2 aguarde os pacotes e dependências serem baixados e instalados configure o caminho para seu repositório em : /usr/share/maven2/conf/settings.xml e pronto o Maven está pronto para usar. Veja o vídeo ilustrativo da instalação do maven em: http://www.screencast.com/t/eeP2P8jws3

Configuração do Mysql - Um problema que senti assim que tentei utilizar o mysql é que não conseguia fazer conexão das ferramentas de administração. Isso acontece porque por default ele é habilitado para escutar conexões somente no localhost(127.0.0.1). Para mudar isso editar o arquivo: /etc/mysql/my.cnf e comentar a linha onde aparece: bind-address:127.0.0.1
Depois reiniciar o mysql com o comando: mysql restart

Habilitar efeitos 3D no Ubuntu - Por último uma coisa opcional mas bem legal é a instalação do pacote de efeitos de Desktop no Ubuntu o que vai dar visual mais legal e efeitos 3D(cubo) no O.S . Para fazer a instalação é bem fácil, utilizando o Synaptic Package Manger basta procurar por compizconfig-settings-manager e depois utilizar o menu do Ubuntu em System> Preferences> ConpizConfig Settings Manager para acessar o painel de configurações de efeitos, são vários, bem legal!

[]s

22 de mar. de 2009

Como instalar um pacote RPM no Ubuntu Linux

Assim que instalamos o Ubuntu e começamos a baixar os pacotes de programas para utilizar com ele nos deparamos com a necessidade de instalar pacotes no formato RPM pois alguns programas ainda disponibilizam somente pacotes com esta extensão que não é imediatamente reconhecida e executada pelo Ubuntu.

Por isso segue uma lista com instruções rápidas de execução de arquivos RPM no Ubuntu.

Primeiramente tem que instalar o Alien que é utilizado para conversão de formatos de arquivo no linux:

sudo apt-get install alien dpkg-dev debhelper build-essential

Aguarde o download dos pacotes que deverá iniciar. Para transformar o pacote desejado para o formato reconhecido pelo Ubuntu utilize o comando:

sudo alien NOME_DO_PACOTE.rpm

Esse comando levará algum tempo e crirá um pacote no mesmo diretório chamado NOME_DO_PACOTE.deb Para instalar o pacote utilize o utilitário dpkg

sudo dpkg -i NOME_DO_PACOTE.deb

Pronto, se o pacote for compatível com Ubunto ele será instalado.

[]s