Wednesday, February 5, 2025

Kubectl Cheat Sheet

Using kubectl within minikube.

----------------------------------------------------------------------
Installation
----------------------------------------------------------------------

# from the minikube project page
curl -LO https://github.com/kubernetes/minikube/releases/latest/download/minikube-linux-amd64

sudo install minikube-linux-amd64 /usr/local/bin/minikube && rm minikube-linux-amd64

ll /usr/local/bin/minikube 

alias kubectl='minikube kubectl --' 

----------------------------------------------------------------------
Minikube Control
----------------------------------------------------------------------

minikube [start|stop|pause|unpause]

----------------------------------------------------------------------
Minikube Inspection
----------------------------------------------------------------------

kubectl get pods
kubectl get pods -A
kubectl get services 
kubectl get services hello-minikube

kubectl describe pod headlamp-57fb76fcdb-f6bsl
kubectl describe pod headlamp-57fb76fcdb-f6bsl --namespace headlamp

----------------------------------------------------------------------
Add-Ons and Services
----------------------------------------------------------------------

minikube addons list
# install
minikube addons enable headlamp

# run addon with name
minikube service headlamp -n headlamp

# run addon
minikube service hello-minikube

# open browser to endpoint, when available from addon
minikube addons open <name>

# run addon when mk starts
minikube start --addons <name1> --addons <name2>

----------------------------------------------------------------------
Deploy Service
----------------------------------------------------------------------

kubectl create deployment hello-minikube --image=kicbase/echo-server:1.0

kubectl expose deployment hello-minikube --type=NodePort --port=8080

kubectl get services hello-minikube

kubectl port-forward service/hello-minikube 7080:8080

----------------------------------------------------------------------
Headlamp Setup
----------------------------------------------------------------------

# install addon - see above
minikube addons enable headlamp

# run addon with name
minikube service headlamp -n headlamp

# get login token
kubectl create token headlamp-admin -n kube-system

# metrics-server helps w/admin
#  uses image registry.k8s.io/metrics-server/metrics-server:v0.7.2
minikube addons enable metrics-server

# See for setup instructions
https://headlamp.dev/docs/latest/installation


~                                                    



Saturday, February 1, 2025

New User Setup Script

Adding a new linux user.

----------------------------------------------------------------------
Basic Ubuntu Script
----------------------------------------------------------------------

#!/bin/bash

USERNAME=$1

# Add user and groups
echo "adding user account: $USERNAME"
sudo adduser $USERNAME
sudo usermod -a -G mygroup $USERNAME

# Add sudo (centOS may require wheel group instead)
sudo usermod -a -G sudo $USERNAME

# Download user PKI cert from remote repo - uses server cert
sudo mkdir -p /home/$USERNAME/.ssh
sudo wget -T 90 -t 1 --certificate=/local/server/cert.pem -0 /home/$USERNAME/.ssh/authorized_keys --no-check-certificate https://keyserver/raw/ds/$USERNAME

# Add starter env
sudo cp -p /home/sample/.bashrc /home/$USERNAME/.

# Set perms
sudo chmod -R 700 /home/$USERNAME
sudo chown -R $USERNAME:$USERNAME /home/$USERNAME




Wednesday, August 28, 2024

Python Packaging

Brief History 

Python builds were traditionally done using:
  • distutils - Python built-in, uses requirements.txt to list dependencies, setup.py for configuration
    • ISSUES: split of deps and config could cause conflicts, and load order confusion

  • setuptools - extended distutils, added automatic install of dependencies
Other packaging tools:
  • wheel - PEP 427 - replaced eggs - build tool with better support for C-library integrations
    • creates .pyc files during installation, to match local interpreter
    • supported in ip >= 1.4 and setuptools >= 0.8
  • PyPI - Python Package Index - online registry of built py libs
among others.

Poetry

Adds main project descritor pyproject.toml to contain project metadata, config, and dependencies.

Some features:
  • can declare different dependency sets, i.e. for prod, dev, and test
  • creates file poetry.lock to define frozen dependencies


Useful Commands

> Create a New Project
poetry new my-package

> Installing existing Project - exclude some dependencies
poetry install --without test,docs

> Installing existing Project - only include some dependencies
poetry install --only dev

> Install or Fix existing Project - sync local to canonical
poetry install --sync

> Get Info about an Installed Lib
poetry show <package-name>


TOML Example


From https://towardsdatascience.com/ditch-requirements-use-poetry-00a936fe9b6d:

[tool.poetry]
name = "my_project"
version = "0.1.0"
description = "Description of my project"
package-mode = true
authors = [
"My Team <team@my_company.com>",
]

[tool.poetry.dependencies]
python = "~3.10"
fastapi = "^0.111.1"
pydantic = "^2.8.2"
Jinja2 = "^3.1.2"
uvicorn = {extras = ["standard"], version = "^0.30.3"}

[tool.poetry.group.dev.dependencies]
pytest = "^8.2.2"
black = "^24.3.0"
pre-commit = "^3.8.0"
mypy = "^1.11"
flake8 = "^7.1.0"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.flake8]
max-line-length = 99
extend-ignore = "E203"

Include From Source

Add the following to include a project in development as a dependency.

[[tool.poetry.source]]
name = "my-artifact-registry-repo"
url = "https://europe-west2-python.pkg.dev/my-gcpproject/my-af-repo/simple"
priority = "explicit"




Wednesday, February 15, 2023

Docker Cheat Sheet


----------------------------------------------------------------------
References
----------------------------------------------------------------------

Docker Engine -- runtime and ops https://docs.docker.com/engine/
Create Docker Containers -- build your own https://docs.docker.com/build/
Orchestrate Containers -- combine containers https://docs.docker.com/compose/

----------------------------------------------------------------------
Basic Docker - Overview
----------------------------------------------------------------------


Basic Docker Architecture

  • Image as container - Binary images of s/w systems published as Containers
  • Versioned - Containers are versioned
  • Decentralized - Your server downloads/stores containers and their parents...warning, this gets large!

Basic Docker Lifecycle

  • Pull containers to use or extend
  • Run containers and expose local resources to them
  • Extend existing containers to create custom run-anywhere binaries

----------------------------------------------------------------------
Basic Docker - Setup
----------------------------------------------------------------------


Install
sudo apt install docker.io
sudo apt install docker-compose


Running without sudo
Assign your user into the docker group. Add group if necessary.

sudo groupadd docker
sudo usermod -a -G docker myuser
# refresh groups or restart server


Other post-install tasks
See https://docs.docker.com/install/linux/linux-postinstall/

Configure - start on boot
On CentOS:
sudo systemctl [enable|disable] docker

----------------------------------------------------------------------
Docker service
----------------------------------------------------------------------

Starting the daemon
sudo service docker start

Start/Stop Docker Service
Debian:
sudo service docker start
CentOS:
sudo systemctl [start|stop] docker 

Test Docker Service
sudo docker run hello-world

----------------------------------------------------------------------
Managing Images
----------------------------------------------------------------------


List all Images
docker images

Image Info - i.e. How do I use this image?
docker image inspect <imageid>

Rename Image...by aliasing the image
docker tag <imageid> <alias>

Remove Image (untagging)
docker rmi <alias>

Remove Unused Images
docker image prune [-a]

Move docker image location off to another drive (for large files)

sudo service docker stop
ps faux|grep docker
sudo ls /var/lib/docker
mv /var/lib/docker <new location> 
sudo service docker start


----------------------------------------------------------------------
Running Containers
----------------------------------------------------------------------


See running containers
docker ps

Launch container from image
docker run -it [-d] [--rm] [--network <name>]  <image_id> 
where:
-d starts detached (daemon)
--rm removes on exit
--network network name to use (see `docker network ls`)

Retain image changes
docker commit <container_id> <group>/<alias>

Attach and execute shell
docker exec -it <container_id> bash

Build image from local Dockerfile
docker build . -t <alias>

Attach to running shell
docker attach <container_id>

Drop out of running shell - but leave running
ctl-p ctl-d

View container logging
docker logs <container_id>

----------------------------------------------------------------------
Creating Images
----------------------------------------------------------------------


Create a Dockerfile with a base image
Search DockerHub for a suitable base
FROM python:latest

Add some standard labels
LABEL org.opencontainers.image.title="Data Service" \
      org.opencontainers.image.version="0.0.1" \
      org.opencontainers.image.authors="aaa@baz.com,bbb@baz.com"

Add some content
ADD data-svc/ /home/python/data-svc/.

Open port for web service
EXPOSE 8080

Attach volumes for in/out of data
VOLUME ["/home/python/data", "/var/log/data-svc"]

Launch a service on container start
ENTRYPOINT ["flask", "--app", "data-svc", "run"]

Build the Docker Image
From the directory containing Dockerfile...
docker build -t <group>/<artifact>:<version> .

----------------------------------------------------------------------
Docker and Docker-Compose Runtime
----------------------------------------------------------------------

Start docker-compose containers
docker-compose up -d



















Friday, October 7, 2022

My Default vimrc File

 Finally putting this down, because I keep re-creating it.

The .vimrc file which normally goes in your user home dir.  There is a default in the vim install dir as well.

Suggestions welcome!




"For gVim - real GUI
set nocompatible
source $VIMRUNTIME/vimrc_example.vim
source $VIMRUNTIME/mswin.vim
behave mswin

" Disable viminfo
set viminfo=""

" to see all colors:
" ls -al /usr/share/vim/vim7*/colors
":colo evening
:colo blue
":colo slate
":colo darkblue
":colo shine

"set lines=45 columns=120

set tabstop=4 softtabstop=4 shiftwidth=4 expandtab autoindent smarttab
set nocindent
set encoding=utf-8 fileencoding=utf-8
set nobackup nowritebackup noswapfile autoread
set number ruler
set hlsearch incsearch ignorecase smartcase

"bash like auto-completion
set wildmenu
set wildmode=list:longest
"
inoremap
"
" for lusty explorer
noremap glr \lr
noremap glf \lf
noremap glb \lb

" use cntrl-h/j/k/l to switch between splits
map j
map k
map l
map h

" display the status line with the filename
set laststatus=2
set noerrorbells
set foldmethod=syntax
set ls=2
set mouse=v

" disable folding
set nofoldenable

Thursday, January 7, 2016

HTTPS Connections with Groovy using Apache HTTPClient

Sample definition of Keystores, their usage and setting up of an HTTPS client connection.

Implemented as a Groovy script, meaning there is no top-level class per se. Could probably be more concise.

//imports removed for brevity


   // Housekeeping - see what the User wants
   //   Groovy note: not declaring a var puts it into "the binding", which makes it globally accessible
   //      * this is only valid for Groovy scripts
   //      * declaring a type (or def) of a var automatically scopes it locally
   config = new Config()
   parseInput(args)

   baseUrl = "https://" + config.host + ":" + config.port + "/myapp/"

   debug "\tBase URL: " + baseUrl

   println "Loading keys..."

   // Create client keystore - this needs to contain:
   //   Client's certificate (i.e., Subject CN == clientname)
   //   Client's private key
   // Needs to be a JKS keystore
   clientKeys  = createKeystore(config.clientKeyFile, config.clientKeyPass)
                                                                                          
   // Truststore for server verification - this needs to contain:
   //   Server certificate: Subject CN == hostname
   //   Server private key
   // Needs to be a JKS keystore
   serverTrust  = createKeystore(config.serverKeyFile, config.serverKeyPass)

   debug "\tclient key: " + clientKeys
   debug "\tserver key: " + serverTrust

   try {
      // ** Create Connection **
      socketFactory = new SSLSocketFactory(
                   SSLSocketFactory.TLS,
                   clientKeys,
                   config.clientKeyPass,
                   serverTrust,
                   null,
                   new TrustSelfSignedStrategy(),                 // not a good choice for production
                   SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); // not a good choice for production

      // Connect socket to enable client PKI authentication
      HttpParams params = new BasicHttpParams();
      params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000);

      SSLSocket socket = (SSLSocket) socketFactory.createSocket(params);
      socket.setEnabledCipherSuites("SSL_RSA_WITH_RC4_128_MD5");

      InetSocketAddress address = new InetSocketAddress(config.host, Integer.parseInt(config.port));
      socketFactory.connectSocket(socket, address, null, params);

      sch = new Scheme("https", new Integer(config.port), socketFactory);

      httpclient = new DefaultHttpClient();
      httpclient.getConnectionManager().getSchemeRegistry().register(sch);

      // Create a local instance of cookie store
      cookieStore = new BasicCookieStore();

      // Create local HTTP context
      localContext = new BasicHttpContext();
      // Bind custom cookie store to the local context
      localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);


      // ****** Example usage *******

      // This is the map-based impl - produces same output as the object-based
      // .... put your own data in here
      def data = [
         "_method" : "POST" ,
         "displayName" : row[DISPLAY_NAME],
         "imageUrlSmall" : row[IMAGE_URL_SMALL] ,
         "imageUrlLarge" : row[IMAGE_URL_LARGE],
         "width" : row[WIDTH],
         "height" : row[HEIGHT]
      ]

      String dataStr = JSONSerializer.toJSON(data)
      try {
         int retries = 5
         while (!created && retries-- > 0) {
         rsp = post (baseUrl + "widget", ["data":dataStr])

         matcher = rsp =~ /\"success\":([\w]+)/

         if (matcher[0]) {
            val =  matcher[0][1]
            debug "\tCREATE RESPONSE: ${val}"

            created = Boolean.parseBoolean(val)
         }

         // This is just for logging
         if (!created) {
            println "ERROR: Creation failed with response: ${rsp}"

            // Detect message failure and retry
            //   Detect failure by GUID invalid format
            matcher = rsp =~ /Property [name].*does not match the required pattern/
            if (matcher[0]) {
               debug "\tERROR RECEIVED:: name is not correct format: ${guid}"
            }
         }
         } // end while
      }
      catch (Exception e) {
          debug "Error creating listing: " + e
          e.printStackTrace()
          guid = null
      }
}

  /**
  *  Return a Keystore from a given filename and password
  */
  def KeyStore createKeystore (filename, password) {
      debug "Default KeyAlgo: " + KeyManagerFactory.getDefaultAlgorithm()
      debug "Default KeyStore: " + KeyStore.getDefaultType()  // jks

      // Pull off file extension
      keyType = filename[-3..-1]
      debug "Requested KeyType: " + keyType

      // Client keystore, for client authentication
      KeyStore keys
      switch (keyType) {
         case "p12":
            keys  = KeyStore.getInstance("pkcs12");
            break
         default:
            keys  = KeyStore.getInstance(KeyStore.getDefaultType());
      }

      FileInputStream instream = new FileInputStream(new File(filename));
      try {
         keys.load(instream, password.toCharArray());
      } finally {
         try { instream.close(); } catch (Exception ignore) {}
      }
      return keys
   }

  def post(url, paramMap) {
      HttpPost httpPost = new HttpPost(url)
      String result

      // Add specific params
      List  nvps = new ArrayList ();
      // These params always present
      nvps.add(new BasicNameValuePair("sample1", "3.6.0-GA"))
      nvps.add(new BasicNameValuePair("dojo.preventCache", "1302893700594"))

      paramMap.each() { key, value ->
         debug "${key} ==> ${value}"
         // Expect the caller to JSON-ize each param, as required
         if (value instanceof List) {
             // Add value multiple times with same key
            value.each {
               nvps.add(new BasicNameValuePair(key, it.toString()))
            }
         }
         else {
            nvps.add(new BasicNameValuePair(key, value))
         }
      }

      httpPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8))

      // Debug
      debug(dump(httpPost))

      debug "Posting request: " + httpPost
      HttpResponse response = httpclient.execute(httpPost, localContext);
      //String response = httpclient.execute(httpPost, new BasicResponseHandler());

      debug "#### RESPONSE TYPE: " + response.class.name

      HttpEntity entity = response.getEntity();

      debug "#### RESPONSE BODY RECEIVED: " + entity.toString()

      // ** Dump results **
      debug "\t" + response.getStatusLine()
      StringBuilder sb = new StringBuilder(255)
      if (entity != null) {

         InputStream ris = entity.getContent()
         OutputStream os = new ByteArrayOutputStream(BUFFER_SIZE)
         byte[] buffer = new byte[BUFFER_SIZE];
         try {
            while ((l = ris.read(buffer)) != -1) {
                os.write(buffer, 0, l)
                sb.append(os.toString())
                os.reset()
            }
         } finally {
             ris.close()
         }

         debug "\tEntity contentLength: " + sb.length()

         result = sb?.toString()

         debug "\t-------------------------------------"
         List cookies = cookieStore.getCookies();
         for (int i = 0; i < cookies.size(); i++) {
            println("\tCookie: " + cookies.get(i));
         }                                                                                    
         debug "\t-------------------------------------"

      }
      else {
          println "Error connecting...check connection details"
          //!! EXIT HERE
          return
      }

      debug "-------------------------------------"
      if (result && result.size() > 256) {
         debug "RESPONSE: " + result.substring(0, 256)
      }
      else {
         debug "RESPONSE: " + result
      }
      debug "-------------------------------------"

      return result
  }

   def debug(stmt) {
       if (config.verbose) {
           println stmt
       }
   }

   def dump(HttpPost post) {
       StringBuilder sb = new StringBuilder(128)

       sb.append("\n\t------------------------------")
       sb.append("\n\tRequestURL: ").append(post.getURI())
       sb.append("\n\tType: ").append(post.getMethod())
       sb.append("\n\tParams: ").append(post.getParams())
       org.apache.http.params.BasicHttpParams
       sb.append("\n\t------------------------------")

       return sb.toString()
   }
         
  class Config {
      String host = "localhost"
      String port = "8443"
      boolean verbose = false
      String inputFile
      String clientKeyFile
      String clientKeyPass
      String serverKeyFile
      String serverKeyPass
  }

   def parseInput(args) {
       if (!args || args.length < 1) {
           usage()
       }
       for(int i=0; i < args.length; i++) {
           it = args[i]
           println "Processing arg: " + it
           switch (it) {
           case "-v":
               debug "Verbose output enabled "
               config.verbose = true
               break
           case "-h":
               it = args[++i]
               debug "Setting Host/Port from: " + it
               // Parse out host and port
               def serverAddr = it.split(":")
               try {
                  if (serverAddr.length > 0 && serverAddr[0] != null) {
                     config.host = serverAddr[0]
                  }
                  if (serverAddr.length > 1 && serverAddr[1] != null) {
                     config.port = serverAddr[1]
                  }
               } catch(Exception e) {
                   usage()
               }
               break
           case "-clientKeys":
               it = args[++i]
               debug "Setting client keyfile to: " + it
               config.clientKeyFile = it
               break
           case "-clientKeyPass":
               it = args[++i]
               debug "Setting client keyfile pwd to: " + it
               config.clientKeyPass = it
               break
           case "-serverKeys":
               it = args[++i]
               debug "Setting server keyfile to: " + it
               config.serverKeyFile = it
               break
           case "-serverKeyPass":
               it = args[++i]
               debug "Setting server keyfile pwd to: " + it
               config.serverKeyPass = it
               break
           default:
               debug "Setting inputFile to: " + it
               config.inputFile = it;
           }
       }
   }

Friday, December 12, 2014

Log4j Sample Config

I often seem to need a reference to log4j and can't find anything online that matches up with my expected results.

So here is my sample from a JBoss server that produces output logs:
log/server.log
log/proj-synchronization.log
log/proj-long-queries.log

What I like about this config is:
  • logs asynchronously
  • allows tuning of debug down to specific packages
  • shows routing of different packages to different output logs

NOTE: many blocks are commented out and left in as examples -- I've tried to denote these by separating their header line.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<!-- ===================================================================== -->
<!--                                                                       -->
<!--  Log4j Configuration                                                  -->
<!--                                                                       -->
<!-- ===================================================================== -->

<!-- $Id: log4j.xml 56612 2006-09-07 15:12:39Z thomas.diesler@jboss.com $ -->

<!--
   | For more configuration information and examples see the Jakarta Log4j
   | website: http://jakarta.apache.org/log4j
 -->

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">

   <!-- ================================= -->
   <!-- Preserve messages in a local file -->
   <!-- ================================= -->

   <!-- A time/date based rolling appender -->
   <appender name="FILE" class="org.jboss.logging.appender.DailyRollingFileAppender">
      <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
      <param name="File" value="${jboss.server.log.dir}/server.log"/>
      <param name="Append" value="false"/>
      <param name="Threshold" value="DEBUG"/>

     <param name="MaxFileSize" value="100KB"/>

      <!-- Rollover at midnight each day -->
      <param name="DatePattern" value="'.'yyyy-MM-dd"/>

      <!-- Rollover at the top of each hour
      <param name="DatePattern" value="'.'yyyy-MM-dd-HH"/>
      -->

      <layout class="org.apache.log4j.PatternLayout">
         <!-- The default pattern: Date Priority [Category] Message\n -->
         <param name="ConversionPattern" value="%d [%t] %-5p [%c] %m%n"/>

         <!-- The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
         <param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
          -->
      </layout>
   </appender>

   <appender name="PROJ-SYNCHRONIZATION" class="org.jboss.logging.appender.DailyRollingFileAppender">
      <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
      <param name="File" value="${jboss.server.home.dir}/log/proj-synchronization.log"/>
      <param name="Append" value="true"/>
      <param name="DatePattern" value="'.'yyyy-MM-dd"/>
      <layout class="org.apache.log4j.PatternLayout">
         <param name="ConversionPattern" value="%d [%t] %-5p [%c] %m%n"/>
      </layout>
   </appender>

   <appender name="PROJ-WEBSERVICE" class="org.jboss.logging.appender.DailyRollingFileAppender">
      <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
      <param name="File" value="${jboss.server.home.dir}/log/proj-webservice.log"/>
      <param name="Append" value="true"/>
      <param name="DatePattern" value="'.'yyyy-MM-dd"/>
      <layout class="org.apache.log4j.PatternLayout">
         <param name="ConversionPattern" value="%d [%t] %-5p [%c] %m%n"/>
      </layout>
   </appender>

   <appender name="QUERY" class="org.jboss.logging.appender.DailyRollingFileAppender">
      <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
      <param name="File" value="${jboss.server.home.dir}/log/proj-long-queries.log"/>
      <param name="Append" value="true"/>
      <param name="DatePattern" value="'.'yyyy-MM-dd"/>
      <layout class="org.apache.log4j.PatternLayout">
         <param name="ConversionPattern" value="%d [%t] %-5p [%c] %m%n"/>
      </layout>
   </appender>


   <!-- A size based file rolling appender

   <appender name="FILE" class="org.jboss.logging.appender.RollingFileAppender">
     <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
     <param name="File" value="${jboss.server.log.dir}/server.log"/>
     <param name="Append" value="false"/>
     <param name="MaxFileSize" value="500KB"/>
     <param name="MaxBackupIndex" value="1"/>

     <layout class="org.apache.log4j.PatternLayout">
       <param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
     </layout>       
   </appender>
   -->

   <!-- ============================== -->
   <!-- Append messages to the console -->
   <!-- ============================== -->
   <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
      <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
      <param name="Target" value="System.out"/>
      <param name="Threshold" value="INFO"/>

      <layout class="org.apache.log4j.PatternLayout">
         <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
      </layout>
   </appender>

   <!-- ====================== -->
   <!-- More Appender examples -->
   <!-- ====================== -->

   <!-- Buffer events and log them asynchronously -->
   <appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
     <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
     <appender-ref ref="FILE"/>
     <appender-ref ref="CONSOLE"/>
     <appender-ref ref="SMTP"/>
   </appender>

   <!-- EMail events to an administrator

   <appender name="SMTP" class="org.apache.log4j.net.SMTPAppender">
     <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
     <param name="Threshold" value="ERROR"/>
     <param name="To" value="admin@myhost.domain.com"/>
     <param name="From" value="nobody@myhost.domain.com"/>
     <param name="Subject" value="JBoss Sever Errors"/>
     <param name="SMTPHost" value="localhost"/>
     <param name="BufferSize" value="10"/>
     <layout class="org.apache.log4j.PatternLayout">
       <param name="ConversionPattern" value="[%d{ABSOLUTE},%c{1}] %m%n"/>
     </layout>
   </appender>
   -->

   <!-- Syslog events

   <appender name="SYSLOG" class="org.apache.log4j.net.SyslogAppender">
     <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
     <param name="Facility" value="LOCAL7"/>
     <param name="FacilityPrinting" value="true"/>
     <param name="SyslogHost" value="localhost"/>
     <layout class="org.apache.log4j.PatternLayout">
       <param name="ConversionPattern" value="[%d{ABSOLUTE},%c{1}] %m%n"/>
     </layout>
   </appender>
   -->

   <!-- Log events to JMS (requires a topic to be created)

   <appender name="JMS" class="org.apache.log4j.net.JMSAppender">
     <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
     <param name="Threshold" value="ERROR"/>
     <param name="TopicConnectionFactoryBindingName" value="java:/ConnectionFactory"/>
     <param name="TopicBindingName" value="topic/MyErrorsTopic"/>
   </appender>
   -->

   <!-- Log events through SNMP

   <appender name="TRAP_LOG" class="org.apache.log4j.ext.SNMPTrapAppender">
     <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
     <param name="ImplementationClassName" value="org.apache.log4j.ext.JoeSNMPTrapSender"/>
     <param name="ManagementHost" value="127.0.0.1"/>
     <param name="ManagementHostTrapListenPort" value="162"/>
     <param name="EnterpriseOID" value="1.3.6.1.4.1.24.0"/>
     <param name="LocalIPAddress" value="127.0.0.1"/>
     <param name="LocalTrapSendPort" value="161"/>
     <param name="GenericTrapType" value="6"/>
     <param name="SpecificTrapType" value="12345678"/>
     <param name="CommunityString" value="public"/>
     <param name="ForwardStackDEBUGWithTrap" value="true"/>
     <param name="Threshold" value="DEBUG"/>
     <param name="ApplicationTrapOID" value="1.3.6.1.4.1.24.12.10.22.64"/>
     <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d,%p,[%t],[%c],%m%n"/>
     </layout>
   </appender>
   -->

   <!--  Emit events as JMX notifications

   <appender name="JMX" class="org.jboss.monitor.services.JMXNotificationAppender">
      <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
     
      <param name="Threshold" value="WARN"/>
      <param name="ObjectName" value="jboss.system:service=Logging,type=JMXNotificationAppender"/>
     
      <layout class="org.apache.log4j.PatternLayout">
         <param name="ConversionPattern" value="%d %-5p [%c] %m"/>
      </layout>
   </appender>
   -->
  
   <!-- ================ -->
   <!-- Limit categories -->
   <!-- ================ -->

   <!-- Limit the org.apache category to INFO as its DEBUG is verbose -->
   <category name="org.apache">
      <priority value="ERROR"/>
   </category>

   <category name="org.apache.log4j">
      <priority value="DEBUG"/>
   </category>


   <!-- Limit the org.jboss.serial (jboss-serialization) to INFO as its DEBUG is verbose -->
   <category name="org.jboss.serial">
      <priority value="ERROR"/>
   </category>

   <!-- Limit the org.jgroups category to WARN as its INFO is verbose -->
   <category name="org.jgroups">
      <priority value="ERROR"/>
   </category>

   <!-- Limit the jacorb category to WARN as its INFO is verbose -->
   <category name="jacorb">
      <priority value="ERROR"/>
   </category>

   <!-- Limit JBoss categories  -->
   <category name="org.jboss">
      <priority value="ERROR"/>
   </category>

   <category name="org.springframework">
      <priority value="ERROR"/>
   </category>

   <category name="org.springframework.web">
      <priority value="error"/>
   </category>

   <category name="org.springframework.scheduling">
      <priority value="error"/>
   </category>

   <category name="org.quartz">
      <priority value="error"/>
   </category>

   <category name="javawebparts">
      <priority value="ERROR"/>
   </category>

   <!-- Limit the JSR77 categories -->
   <category name="org.jboss.management">
      <priority value="ERROR"/>
   </category>

   <category name="org.hibernate">
      <priority value="warn"/>
   </category>

   <category name="org.hibernate.SQL">
      <priority value="warn"/>
   </category>

   <category name="net.sf.ehcache">
      <priority value="ERROR"/>
   </category>

   <category name="com.proj.ws">
      <priority value="error"/>
   </category>

   <category name="com.myapp">
      <priority value="DEBUG"/>
   </category>
   <category name="com.myapp.service">
      <priority value="DEBUG"/>
   </category>
   <category name="com.myapp.spring">
      <priority value="DEBUG"/>
   </category>

   <category name="com.myapp.service.UserService">
      <priority value="error"/>
   </category>

   <!-- Flooring utils are not usually useful in troubleshooting -->
   <category name="com.myapp.util">
      <priority value="DEBUG"/>
   </category>

   <category name="com.myapp.servlet.filter">
      <priority value="DEBUG"/>
   </category>

   <category name="com.proj.ws.synchronization" additivity="false">
      <priority value="error"/>
      <appender-ref ref="PROJ-SYNCHRONIZATION"/>
   </category>

   <category name="com.proj.ws.longQuery" additivity="false">
      <priority value="ERROR"/>
      <appender-ref ref="QUERY"/>
   </category>

   <!-- Enable JBossWS message tracing
    <priority value="error" class="org.jboss.logging.XLevel"/>
   -->
   <category name="jbossws.SOAPMessage">
     <priority value="error"/>
   </category>

   <!-- Decrease the priority threshold for the org.jboss.varia category -->
   <category name="org.jboss.varia">
     <priority value="error"/>
   </category>

   <!-- Show the evolution of the DataSource pool in the logs [inUse/Available/Max]

   <category name="org.jboss.resource.connectionmanager.JBossManagedConnectionPool">
     <priority value="error" class="org.jboss.logging.XLevel"/>
   </category>
   -->

   <!--

      | An example of enabling the custom DEBUG level priority that is used
      | by the JBoss internals to diagnose low level details. This example
      | turns on DEBUG level msgs for the org.jboss.ejb.plugins package and its
      | subpackages. This will produce A LOT of logging output.
   <category name="org.jboss.system">
     <priority value="DEBUG" class="org.jboss.logging.XLevel"/>
   </category>
   <category name="org.jboss.ejb.plugins">
     <priority value="DEBUG" class="org.jboss.logging.XLevel"/>
   </category>
   -->
 
   <!--
       | Logs these events to SNMP:

           - server starts/stops
           - cluster evolution (node death/startup)
           - When an EJB archive is deployed (and associated verified messages)
           - When an EAR archive is deployed
         
   <category name="org.jboss.system.server.Server">
     <priority value="INFO" />
     <appender-ref ref="TRAP_LOG"/>
   </category>
 
   <category name="org.jboss.ha.framework.interfaces.HAPartition.lifecycle">
     <priority value="INFO" />
     <appender-ref ref="TRAP_LOG"/>
   </category>

   <category name="org.jboss.deployment.MainDeployer">
     <priority value="ERROR" />
     <appender-ref ref="TRAP_LOG"/>
   </category>
  
   <category name="org.jboss.ejb.EJBDeployer">
     <priority value="INFO" />
     <appender-ref ref="TRAP_LOG"/>
   </category>
  
   <category name="org.jboss.deployment.EARDeployer">
     <priority value="INFO" />
     <appender-ref ref="TRAP_LOG"/>
   </category>
 
   -->

   <!-- ======================= -->
   <!-- Setup the Root category -->
   <!-- ======================= -->

   <root>
       <appender-ref ref="FILE"/>
       <appender-ref ref="CONSOLE"/>
       <!-- use if routing all categories to an appender-ref <level value="OFF" /> -->
   </root>

   <!-- Clustering logging -->

   <!-- Uncomment the following to redirect the org.jgroups and
      org.jboss.ha categories to a cluster.log file.

   <appender name="CLUSTER" class="org.jboss.logging.appender.RollingFileAppender">
     <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
     <param name="File" value="${jboss.server.log.dir}/cluster.log"/>
     <param name="Append" value="false"/>
     <param name="MaxFileSize" value="500KB"/>
     <param name="MaxBackupIndex" value="1"/>

     <layout class="org.apache.log4j.PatternLayout">
       <param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
     </layout>
   </appender>
   <category name="org.jgroups">
     <priority value="DEBUG" />
     <appender-ref ref="CLUSTER"/>
   </category>
   <category name="org.jboss.ha">
     <priority value="DEBUG" />
     <appender-ref ref="CLUSTER"/>
   </category>
   -->

</log4j:configuration>