/*
* Created on 22-Sep-2004
* Created by Paul Gardner
* Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package org.gudy.azureus2.core3.util;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.platform.PlatformManager;
import org.gudy.azureus2.platform.PlatformManagerCapabilities;
import org.gudy.azureus2.platform.PlatformManagerFactory;
/**
* @author parg
*
*/
import java.io.*;
import java.util.*;
public class
AEDiagnostics
{
// these can not be set true and have a usable AZ!
public static final boolean ALWAYS_PASS_HASH_CHECKS = false;
public static final boolean USE_DUMMY_FILE_DATA = false;
public static final boolean CHECK_DUMMY_FILE_DATA = false;
// these can safely be set true, things will work just slower
public static final boolean DEBUG_MONITOR_SEM_USAGE = false;
public static final boolean DEBUG_THREADS = true; // Leave this on by default for the moment
public static final boolean TRACE_DIRECT_BYTE_BUFFERS = false;
public static final boolean TRACE_DBB_POOL_USAGE = false;
public static final boolean PRINT_DBB_POOL_USAGE = false;
public static final boolean TRACE_TCP_TRANSPORT_STATS = false;
public static final boolean TRACE_CONNECTION_DROPS = false;
static{
if ( ALWAYS_PASS_HASH_CHECKS ){
System.out.println( "**** Always passing hash checks ****" );
}
if ( USE_DUMMY_FILE_DATA ){
System.out.println( "**** Using dummy file data ****" );
}
if ( CHECK_DUMMY_FILE_DATA ){
System.out.println( "**** Checking dummy file data ****" );
}
if ( DEBUG_MONITOR_SEM_USAGE ){
System.out.println( "**** AEMonitor/AESemaphore debug on ****" );
}
if ( TRACE_DIRECT_BYTE_BUFFERS ){
System.out.println( "**** DirectByteBuffer tracing on ****" );
}
if ( TRACE_DBB_POOL_USAGE ){
System.out.println( "**** DirectByteBufferPool tracing on ****" );
}
if ( PRINT_DBB_POOL_USAGE ){
System.out.println( "**** DirectByteBufferPool printing on ****" );
}
if ( TRACE_TCP_TRANSPORT_STATS ){
System.out.println( "**** TCP_TRANSPORT_STATS tracing on ****" );
}
int maxFileSize = 256 * 1024;
try {
String logSize = System.getProperty("diag.logsize", null);
if (logSize != null) {
if (logSize.toLowerCase().endsWith("m")) {
maxFileSize = Integer.parseInt(logSize.substring(0,
logSize.length() - 1)) * 1024 * 1024;
} else {
maxFileSize = Integer.parseInt(logSize);
}
}
} catch (Throwable t) {
}
MAX_FILE_SIZE = maxFileSize;
}
private static final int MAX_FILE_SIZE; // get two of these per logger type
private static final String CONFIG_KEY = "diagnostics.tidy_close";
private static File debug_dir;
private static File debug_save_dir;
private static boolean started_up;
private static volatile boolean startup_complete;
private static boolean enable_pending_writes;
private static Map<String,AEDiagnosticsLogger> loggers = new HashMap<String, AEDiagnosticsLogger>();
protected static boolean logging_enabled;
protected static boolean loggers_enabled;
private static List<AEDiagnosticsEvidenceGenerator> evidence_generators = new ArrayList<AEDiagnosticsEvidenceGenerator>();
public static synchronized void
startup(
boolean _enable_pending )
{
if ( started_up ){
return;
}
started_up = true;
enable_pending_writes = _enable_pending;
try{
// Minimize risk of loading to much when in transitory startup mode
boolean transitoryStartup = System.getProperty("transitory.startup", "0").equals("1");
if ( transitoryStartup ){
// no xxx_?.log logging for you!
loggers_enabled = false;
// skip tidy check and more!
return;
}
debug_dir = FileUtil.getUserFile( "logs" );
debug_save_dir = new File( debug_dir, "save" );
COConfigurationManager.addAndFireParameterListeners(
new String[]{
"Logger.Enabled",
"Logger.DebugFiles.Enabled",
},
new ParameterListener()
{
public void
parameterChanged(
String parameterName)
{
logging_enabled = COConfigurationManager.getBooleanParameter( "Logger.Enabled" );
loggers_enabled = logging_enabled && COConfigurationManager.getBooleanParameter( "Logger.DebugFiles.Enabled");
if ( !loggers_enabled ){
loggers_enabled = Constants.IS_CVS_VERSION || COConfigurationManager.getBooleanParameter( "Logger.DebugFiles.Enabled.Force" );
}
}
});
boolean was_tidy = COConfigurationManager.getBooleanParameter( CONFIG_KEY );
new AEThread2( "asyncify", true )
{
public void
run()
{
SimpleTimer.addEvent("AEDiagnostics:logCleaner",SystemTime.getCurrentTime() + 60000
+ RandomUtils.nextInt(15000), new TimerEventPerformer() {
public void perform(TimerEvent event) {
cleanOldLogs();
}
});
}
}.start();
if ( debug_dir.exists()){
boolean save_logs = System.getProperty( "az.logging.save.debug", "true" ).equals( "true" );
long now = SystemTime.getCurrentTime();
File[] files = debug_dir.listFiles();
if ( files != null ){
boolean file_found = false;
for (int i=0;i<files.length;i++){
File file = files[i];
if ( file.isDirectory()){
continue;
}
if ( !was_tidy ){
file_found = true;
if ( save_logs ){
if ( !debug_save_dir.exists()){
debug_save_dir.mkdir();
}
FileUtil.copyFile( file, new File( debug_save_dir, now + "_" + file.getName()));
}
}
}
if ( file_found ){
Logger.logTextResource(new LogAlert(LogAlert.UNREPEATABLE,
LogAlert.AT_WARNING, "diagnostics.log_found"),
new String[] { debug_save_dir.toString() });
}
}
}else{
debug_dir.mkdir();
}
AEJavaManagement.initialise();
}catch( Throwable e ){
// with webui we don't have the file stuff so this fails with class not found
if ( !(e instanceof NoClassDefFoundError )){
Debug.printStackTrace( e );
}
}finally{
startup_complete = true;
}
}
public static void
dumpThreads()
{
AEJavaManagement.dumpThreads();
}
/**
*
*/
private static synchronized void cleanOldLogs() {
try {
long now = SystemTime.getCurrentTime();
// clear out any really old files in the save-dir
File[] files = debug_save_dir.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (!file.isDirectory()) {
long last_modified = file.lastModified();
if (now - last_modified > 10 * 24 * 60 * 60 * 1000L) {
file.delete();
}
}
}
}
} catch (Exception e) {
}
}
public static boolean
isStartupComplete()
{
return( startup_complete );
}
public static File
getLogDir()
{
startup( false );
return( debug_dir );
}
public static synchronized void
flushPendingLogs()
{
for ( AEDiagnosticsLogger logger: loggers.values()){
logger.writePending();
}
enable_pending_writes = false;
}
public static synchronized AEDiagnosticsLogger
getLogger(
String name )
{
AEDiagnosticsLogger logger = loggers.get(name);
if ( logger == null ){
startup( false );
logger = new AEDiagnosticsLogger( debug_dir, name, MAX_FILE_SIZE, !enable_pending_writes );
loggers.put( name, logger );
}
return( logger );
}
public static void
logWithStack(
String logger_name,
String str )
{
log( logger_name, str + ": " + Debug.getCompressedStackTrace());
}
public static void
log(
String logger_name,
String str )
{
getLogger( logger_name ).log( str );
}
public static void
markDirty()
{
try{
COConfigurationManager.setParameter( CONFIG_KEY, false );
COConfigurationManager.save();
}catch( Throwable e ){
Debug.printStackTrace( e );
}
}
public static boolean
isDirty()
{
return( !COConfigurationManager.getBooleanParameter( CONFIG_KEY ));
}
public static void
markClean()
{
try{
COConfigurationManager.setParameter( CONFIG_KEY, true );
COConfigurationManager.save();
}catch( Throwable e ){
Debug.printStackTrace( e );
}
}
private static final String[][]
bad_dlls = {
{ "niphk", "y", },
{ "nvappfilter", "y", },
{ "netdog", "y", },
{ "vlsp", "y", },
{ "imon", "y", },
{ "sarah", "y", },
{ "MxAVLsp", "y", },
{ "mclsp", "y", },
{ "radhslib", "y", },
{ "winsflt", "y", },
{ "nl_lsp", "y", },
{ "AxShlex", "y", },
{ "iFW_Xfilter", "y", },
{ "gapsp", "y", },
{ "WSOCKHK", "n", },
{ "InjHook12", "n", },
{ "FPServiceProvider","n", },
{ "SBLSP.dll", "y" },
{ "nvLsp.dll", "y" },
};
public static void
checkDumpsAndNatives()
{
try{
PlatformManager p_man = PlatformManagerFactory.getPlatformManager();
if ( p_man.getPlatformType() == PlatformManager.PT_WINDOWS &&
p_man.hasCapability( PlatformManagerCapabilities.TestNativeAvailability )){
for (int i=0;i<bad_dlls.length;i++){
String dll = bad_dlls[i][0];
String load = bad_dlls[i][1];
if ( load.equalsIgnoreCase( "n" )){
continue;
}
if ( !COConfigurationManager.getBooleanParameter( "platform.win32.dll_found." + dll, false )){
try{
if ( p_man.testNativeAvailability( dll + ".dll" )){
COConfigurationManager.setParameter( "platform.win32.dll_found." + dll, true );
String detail = MessageText.getString( "platform.win32.baddll." + dll );
Logger.logTextResource(
new LogAlert(
LogAlert.REPEATABLE,
LogAlert.AT_WARNING,
"platform.win32.baddll.info" ),
new String[]{ dll + ".dll", detail });
}
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
}
File app_dir = new File( SystemProperties.getApplicationPath());
if ( app_dir.canRead()){
File[] files = app_dir.listFiles();
File most_recent_dump = null;
long most_recent_time = 0;
long now = SystemTime.getCurrentTime();
long one_week_ago = now - 7*24*60*60*1000;
for (int i=0;i<files.length;i++){
File f = files[i];
String name = f.getName();
if ( name.startsWith( "hs_err_pid" )){
long last_mod = f.lastModified();
if ( last_mod > most_recent_time && last_mod > one_week_ago){
most_recent_dump = f;
most_recent_time = last_mod;
}
}
}
if ( most_recent_dump!= null ){
long last_done =
COConfigurationManager.getLongParameter( "diagnostics.dump.lasttime", 0 );
if ( last_done < most_recent_time ){
COConfigurationManager.setParameter( "diagnostics.dump.lasttime", most_recent_time );
analyseDump( most_recent_dump );
}
}
}
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
protected static void
analyseDump(
File file )
{
System.out.println( "Analysing " + file );
try{
LineNumberReader lnr = new LineNumberReader( new FileReader( file ));
try{
boolean float_excep = false;
String[] bad_dlls_uc = new String[bad_dlls.length];
for (int i=0;i<bad_dlls.length;i++){
String dll = bad_dlls[i][0];
bad_dlls_uc[i] = (dll + ".dll" ).toUpperCase();
}
String alcohol_dll = "AxShlex";
List<String> matches = new ArrayList<String>();
while( true ){
String line = lnr.readLine();
if ( line == null ){
break;
}
line = line.toUpperCase();
if (line.indexOf( "EXCEPTION_FLT") != -1 ){
float_excep = true;
}else{
for (int i=0;i<bad_dlls_uc.length;i++){
String b_uc = bad_dlls_uc[i];
if ( line.indexOf( b_uc ) != -1 ){
String dll = bad_dlls[i][0];
if ( dll.equals( alcohol_dll )){
if ( float_excep ){
matches.add( dll );
}
}else{
matches.add( dll );
}
}
}
}
}
for (int i=0;i<matches.size();i++){
String dll = matches.get(i);
String detail = MessageText.getString( "platform.win32.baddll." + dll );
Logger.logTextResource(
new LogAlert(
LogAlert.REPEATABLE,
LogAlert.AT_WARNING,
"platform.win32.baddll.info" ),
new String[]{ dll + ".dll", detail });
}
}finally{
lnr.close();
}
}catch( Throwable e){
Debug.printStackTrace( e );
}
}
public static void
addEvidenceGenerator(
AEDiagnosticsEvidenceGenerator gen )
{
synchronized( evidence_generators ){
evidence_generators.add( gen );
}
}
public static void
removeEvidenceGenerator(
AEDiagnosticsEvidenceGenerator gen )
{
synchronized( evidence_generators ){
evidence_generators.remove( gen );
}
}
public static void
generateEvidence(
PrintWriter _writer )
{
IndentWriter writer = new IndentWriter( _writer );
synchronized( evidence_generators ){
for (int i=0;i<evidence_generators.size();i++){
try{
evidence_generators.get(i).generate( writer );
}catch( Throwable e ){
e.printStackTrace( _writer );
}
}
}
writer.println( "Memory" );
try{
writer.indent();
Runtime rt = Runtime.getRuntime();
writer.println( "max=" + rt.maxMemory() + ",total=" + rt.totalMemory() + ",free=" + rt.freeMemory());
}finally{
writer.exdent();
}
}
}