, ,

IFDEBUG 2: Как жить без фаталов?

» опубликован
» Способ реализации: cJass
» Тип: Наработка
Думаю многие помнят небольшую, но очень полезную библиотечку от Doc которая помогала сохранять дебаг логи на хард по средствам прелоада и библиотечку от Скорпи, которая помогала контролировать в коде соблюдение различных условий.
Думаю, те кто пользовались, остались довольны, как и я.
Так вот, недавно Faion малость усовершенствовал первую, а скорпи присоединил вторую. Надеюсь, док и faion будут не против.
В результате получилось отличное средство от геморроя и немного от фаталов!

Инструкции

//     Instructions:
//
//     Пишет информацию об условии в лог, если условие ВЫПОЛНИЛОСЬ:
// IFDEBUG( ARGUMENT ) 
//
//     Пишет информацию в лог, если условие НЕ ВЫПОЛНЕНО и УНИЧТОЖАЕТ весь текущий поток:
// ASSERT( ARGUMENT ) 
//
//     Пишет информацию об условии в лог, если условие ВЫПОЛНИЛОСЬ и выходит из функции со значением, указанным во втором аргументе:
// IFDEBUG( ARGUMENT, RET )
//
// Заметка: Если функция ничего не возвращает, но вы в любом случае хотите её остановить, используйте пробел, как: IFDEBUG(u == null, );
// Заметка: Лог пишется только в режиме отладки JNGP - "Debug Mode".

Code

//     Instructions:
//
//     Writes log if the condition is satisfied:
// IFDEBUG( ARGUMENT ) 
//
//     Writes log if the condition is NOT satisfied and TERMINATES its thread:
// ASSERT( ARGUMENT ) 
//
//     Writes log if the condition is satisfied and returns value from the second argument:
// IFDEBUG( ARGUMENT, RET )
//
// Note: If the function returns nothing but you wanna stop it anyway, use the space like: IFDEBUG(u == null, );
// Note: Log is written only in JNGP "Debug Mode".

//     Configuration:
#define
{
    Debug = true
    private SavePath = NS_SNW_LOGS\\Logs
    private PerformanceSavePath = NS_SNW_LOGS\\PerformanceLogs
    private SaveOnHardDrive = true
    private HardDriveLetter = C
    private AutoSaveLog = true
    private LogSavePeriod = 5.0
}

// by Faion, 2012
// by DoctorGester (Doc), 2011

library DebugLog initializer DebugLogInit
{
    public bool EnableLogging = true
    private string array DebugLog
    private string array PerformanceDebugLog
    private int CurrentString = 0
    private int miliSeconds = 0
    private int Seconds = 0
    private int Minutes = 0
    private int Hours = 0
    private constant int StringLimit = 200
    
    private int pastVal = 0;
    private int PerformanceString = 0
    
    void PerformanceLogAdd()
    {
        if (!EnableLogging)
        {
            return
        }
        string min = I2S(Minutes)
        string sec = I2S(Seconds)
        string msec = I2S(miliSeconds)
        if (Minutes < 10)
        {
            min = "0" + min
        }
        if (Seconds < 10)
        {
            sec = "0" + sec
        }
        if (miliSeconds < 10)
        {
            msec = "0" + msec
        }
        location loc = Location(0,0);
        int hId = GetHandleId(loc);
        
        RemoveLocation(loc);
        loc = null;
        PerformanceDebugLog[PerformanceString] = PerformanceDebugLog[PerformanceString] + ("[" + I2S(Hours)+":" + min + ":" + sec + ":" + msec + "] " + I2S(hId-0x100000) + "\n")
        if (StringLength(PerformanceDebugLog[PerformanceString]) >= StringLimit)
        {
            PerformanceString++
        }
    }
    
    void PerformanceLogUpdate()
    {
        if (!EnableLogging)
        {
            return
        }
        PreloadGenClear()
        PreloadGenStart()
        int i = 0
        while (i <= PerformanceString)
        {
            Preload("\")\n" + PerformanceDebugLog[i] + "\n(\"")
            i++
        }
        #if SaveOnHardDrive
            PreloadGenEnd(`HardDriveLetter` + ":\\" + `PerformanceSavePath` + ".txt")
        #else
            PreloadGenEnd("\\" + `PerformanceSavePath` + ".txt")
        #endif
    }
    
    void LogAdd(string s)
    {
        if (!EnableLogging)
        {
            return
        }
        string min = I2S(Minutes)
        string sec = I2S(Seconds)
        string msec = I2S(miliSeconds)
        if (Minutes < 10)
        {
            min = "0" + min
        }
        if (Seconds < 10)
        {
            sec = "0" + sec
        }
        if (miliSeconds < 10)
        {
            msec = "0" + msec
        }
        DebugLog[CurrentString] = DebugLog[CurrentString] + ("[" + I2S(Hours)+":" + min + ":" + sec + ":" + msec + "] " + s + "\n")
        if (StringLength(DebugLog[CurrentString]) >= StringLimit)
        {
            CurrentString++
        }
    }
    
    void LogClear()
    {
        int i = 0
        while (i <= CurrentString)
        {
            DebugLog[i] = ""
            i++
        }
        CurrentString = 0
    }
    
    void LogUpdate()
    {
        if (!EnableLogging)
        {
            return
        }
        PreloadGenClear()
        PreloadGenStart()
        int i = 0
        while (i <= CurrentString)
        {
            Preload("\")\n" + DebugLog[i] + "\n(\"")
            i++
        }
        #if SaveOnHardDrive
            PreloadGenEnd(`HardDriveLetter` + ":\\" + `SavePath` + ".txt")
        #else
            PreloadGenEnd("\\" + `SavePath` + ".txt")
        #endif
    }
    
    private void DebugLogOnTimer()
    {
        miliSeconds++
        if (miliSeconds > 99)
        {
            miliSeconds = 0
            Seconds++
            if (Seconds > 59)
            {
                Seconds = 0
                Minutes++
                if (Minutes > 59)
                {
                    Minutes = 0
                    Hours++
                }
            }
        }
    }

    private void DebugLogInit()
    {
        #if AutoSaveLog
            TimerStart(CreateTimer(), LogSavePeriod, true, function LogUpdate)
            TimerStart(CreateTimer(), LogSavePeriod, true, function PerformanceLogUpdate)
        #endif
        TimerStart(CreateTimer(), 0.01, true, function DebugLogOnTimer)
        TimerStart(CreateTimer(), 0.10, true, function PerformanceLogAdd)
        LogAdd("By FaionBezarius. Last compilation: " + `DATE` + " " + `TIME`)
	#if Debug 
        	BJDebugMsg("By FaionBezarius. Last compilation: " + `DATE` + " " + `TIME`)
	#endif
    }
	
	
//   by ScorpioT1000, 2009
//   powered by AdicHelper(cJass.xgm.ru)

    #define private assert_color = "FF404040"

    nothing Ifdebug_debug_msg(string message, integer whichPlayer) {
    	LogAdd("|c"+assert_color+"Debug: "+message+"|r")
    }
    
    #define private DMSGFUNC = Ifdebug_debug_msg
    
	#define IFDEBUGF(ARG,DEST_PLAYER) =  
    #define IFDEBUGFA(ARG,DEST_PLAYER) = {
        if(ARG) {
        } else {
			I2R(2/0)
		}
    }
	    #define IFDEBUGR(ARG,WHATRET,DEST_PLAYER) = {
        if(ARG) {
            return WHATRET
        }
    }
	
#if DEBUG == 1
    #setdef IFDEBUGF(ARG,DEST_PLAYER) = {
        if(ARG) {
            DMSGFUNC(`FUNCNAME` + ": " + `ARG`,DEST_PLAYER)
        }
    }
    #setdef IFDEBUGFA(ARG,DEST_PLAYER) = {
        if(ARG) {
        } else {
		DMSGFUNC(`FUNCNAME` + ": " + `ARG` + " failed",DEST_PLAYER)
		I2R(2/0)
		}
    }
    
    #setdef IFDEBUGR(ARG,WHATRET,DEST_PLAYER) = {
        if(ARG) {
            DMSGFUNC(`FUNCNAME` + ": " + `ARG`,DEST_PLAYER)
            return WHATRET
        }
    }
#endif
    
    //overloading
    #define {
    ASSERT(ARGUMENT) = IFDEBUGFA(ARGUMENT, -1)
        IFDEBUG(ARGUMENT) = IFDEBUGF(ARGUMENT, -1) // with condition to all players
        IFDEBUG(ARGUMENT,RET) = IFDEBUGR(ARGUMENT,RET, -1) // with condition and return to all players
        IFDEBUGP(ARGUMENT,DEST_PLAYER) = IFDEBUGF(A,DEST_PLAYER) // with condition to one player
        IFDEBUGP(ARGUMENT,RET,DEST_PLAYER) = IFDEBUGF(A,RET,DEST_PLAYER) // with condition and return to one players
    }
    
}

Примеры

// функция остановится и в лог будет записано, что выполнено условие "u == null" в функции "foo"
function foo takes unit u returns nothing
    IFDEBUG(u == null, )
    KillUnit(u)
endfunction

// если не будет выполнено условие "x > 0", будет остановлена вся цепочка вызывавших ее функций и в логе будет запись об этой функции и условии
function xab takes integer a, integer b, integer c returns integer
    local integer x = a * b * c
    ASSERT(x > 0)
    return SquareRoot(x)
endfunction

// вернет false если хотябы один из юнитов равен null, запишет всё в лог
function bvc takes nothing returns boolean
    local unit u = GetTriggerUnit()
    local unit t = GetSpellTargetUnit()
    IFDEBUG(u == 0 or t == null, false)
    // ...
    return true
endfunction
Вот для тех, кто хочет понять истинный смысл: это просто - ты вставляешь этот код ВЕЗДЕ, во всех функциях и т.п. Естественно, доводишь до того состояния, чтобы ни одной ошибки не выходило. И когда проводишь рефакторинг, т.е. меняешь что-то внутри, меняешь логику или просто добавляешь функционал, проводишь ручные тесты и видишь ошибки - их легко исправить, сразу ясно, где и что случилось.
Это полный выигрыш перед вашими if () then BJDebugMsg("АЛАЛАЛААЛМАМА").
Т.е. выигрыш в том, что ты оставляешь эти проверки постоянно, а не на время. Тут сразу и префиксы есть и всё красиво написано.


Просмотров: 6 505

» Лучшие комментарии


Clamp #1 - 6 лет назад -2
Неплохо. Хотя бы раз что то полезное на preload exploit сделали.
Забавно, но в ск2 это стандартная функция.
FYAN #2 - 6 лет назад 0
однозначно зачет)
YellowStar #3 - 6 лет назад 0
  1. Никогда не используйте в системах define<int=integer> и иже с ними, я например пользуюсь полным написанием, а int,float,void,bool - название соответствующих переменных (красивая подсветочка же).
  1. Эта система не актуальна. Любой код ты делаешь на сторонней карте примере (если проект больше конечно), там же его тестируешь, и лишь потом переносишь в карту.
  1. У меня не разу не было фаталов, хотя я работаю всегда с ExecuteFunc.
  1. Отлавливать баги, это функция поможет только индусам использующим cJass, так как без этй надстройки, код красивый и удобно читаемый. Всегда. (ну за исключением zinc)
Минус не нужной наработке.
alexprey #4 - 6 лет назад (отредактировано ) 0
YellowStar, в любом случае код все же приходиться переносить, баги могут появиться неожиданно у пользователей, вот в этот момент то и требуется лог с инфой. Хотя то, что требуется cJass парсер напрягает, так как юзаю онли vJass. Все же не признаю смеси языков.
Идея в общем то забавная, но не вижу в ней толкового смысла
убило вот что
if (ARG) {
} else {
    I2R(2/0)
}
Кто вас учил так писать????
ScorpioT1000 #5 - 6 лет назад (отредактировано ) 0
alexprey, это быстрее чем if(not ..) {
YellowStar, шёл бы ты отсюда, пастушок.
alexprey #6 - 6 лет назад 0
ScorpioT1000, опять неоправданные нано секунды?
ScorpioT1000 #7 - 6 лет назад 0
alexprey, ты не понимаешь что тут можно ее вставить в циклы например?
YellowStar #8 - 6 лет назад -5
ScorpioT1000:
alexprey, ты не понимаешь что тут можно ее вставить в циклы например?
И? Ты такой тупой ей богу, эти наносекунды погоды не сделают. вообще
alexprey #9 - 6 лет назад 3
ScorpioT1000, не притворяйся идиотом.
1000 итераций цикла, и это затраты перейдут в микро. По сравнению со сравнением это настолько мало, что можно пренебречь этой фигней. И вообще если так трестись из-за наносекунд может тогда весь код писать на чистом jass с ручной оптимизацией и обусфикацией?
ScorpioT1000 #10 - 6 лет назад (отредактировано ) 0
Дождливую погоду я могу сделать разве что у кого-то во рту.
И вообще если так трестись из-за наносекунд может тогда весь код писать на чистом jass с ручной оптимизацией и обусфикацией?
Зачем? В моей части кода всё и так идеально =)
Кстати в идеале на jass надо длину имен функций и переменных минимизировать, особенно массивы, вот почему обфускаторы всегда мастхев =)
Вот для тех кто хочет понять истинный смысл это просто - ты вставляешь этот код ВЕЗДЕ во всех функциях итп. Естественно доводишь до того состояния, чтобы ни одной ошибки не выходило. И когда проводишь рефакторинг, т.е. меняешь что-то внутри, меняешь логику или просто добавляешь функционал, проводишь ручные тесты и видишь ошибки - их легко исправить, сразу ясно, где и что случилось. Это полный выигрыш перед вашими if () then BJDebugMsg("АЛАЛАЛААЛМАМА").
Т.е. выигрыш в том, что ты оставляешь эти проверки постоянно, а не на время. Тут сразу и префиксы есть и всё красиво написано.
alexprey #11 - 6 лет назад 0
при этом сделано как if () then DJDebugMsg <_<
ScorpioT1000 #12 - 6 лет назад 0
alexprey, ты знаешь понятие "внедрение" ? Так вот IFDEBUG предполагает постоянное, комплексное использование, а не временное.
Вот ты подсказал кстати. Можно при отключенном дебаге сделать те же проверки тока без вывода в лог.
done =)
2 комментария удалено
YellowStar #15 - 6 лет назад -6
ScorpioT1000:
alexprey, ты знаешь понятие "внедрение" ? Так вот IFDEBUG предполагает постоянное, комплексное использование, а не временное.
Вот ты подсказал кстати. Можно при отключенном дебаге сделать те же проверки тока без вывода в лог.
done =)
Чем тебе debug call мешает и его включение и отключение? Также комплексно включил, отключил одним нажатием. Ты просто не шаришь, и производишь говно на свет которое - не нужно.
alexprey #16 - 6 лет назад 2
YellowStar, скорп шарящий, но иногда несет пургу
Msey #17 - 6 лет назад 0
Понтов много, а толк практически нулевой..имхо)
Однако хозяин барин.
tenistay #18 - 6 лет назад -4
"которая помогала сохранять дебаг логи на хард по средствам прелоада" ты вообще на русском языке пишешь? Или это финальная стадия компьютерной болезни?
Faion #19 - 6 лет назад 0
YellowStar:
  1. Никогда не используйте в системах define<int=integer> и иже с ними, я например пользуюсь полным написанием, а int,float,void,bool - название соответствующих переменных (красивая подсветочка же).
  1. Эта система не актуальна. Любой код ты делаешь на сторонней карте примере (если проект больше конечно), там же его тестируешь, и лишь потом переносишь в карту.
  1. У меня не разу не было фаталов, хотя я работаю всегда с ExecuteFunc.
  1. Отлавливать баги, это функция поможет только индусам использующим cJass, так как без этй надстройки, код красивый и удобно читаемый. Всегда. (ну за исключением zinc)
Минус не нужной наработке.
Кран, это не только ifdebug, но и помогает при правильном использовании отловить системы которые много жрут памяти, или попросту создают утечки.
alexprey #20 - 6 лет назад 0
nothing Ifdebug_debug_msg(string message, integer whichPlayer) {
    	LogAdd("|c"+assert_color+"Debug: "+message+"|r")
    }
везде void, а тут nothing, как так то?
ScorpioT1000 #21 - 6 лет назад 0
alexprey, опенсурс x)
Faion #22 - 6 лет назад 0
alexprey, скорп просто прикрутил свой код к моему :)
Темак #23 - 6 лет назад 3
узнать бы при каких условиях случается фатал
Daro #24 - 5 лет назад 0
таким как я не понять
ScorpioT1000 #25 - 3 года назад 0

Вот это с моим последним комментом помогает выводить автоматически в лог