Статья: Программируем под IIS на Visual C++
Название: Программируем под IIS на Visual C++ Раздел: Рефераты по информатике, программированию Тип: статья | ||||||||||||||||||||||||||||||||||||||||
Одной из распространенных задач администрирования web-сайтов является анализ log-файлов и сбор данных из них. Поговорим об этой задаче на примере IIS 5.0 (Internet Information Service). В связи с тем, что данный HTTP сервер поддерживает несколько форматов таких файлов (формат W3C, формат NCSA, а также свой формат IIS), анализ log-файлов превращается в довольно трудоемкую задачу. Кроме того для формата W3C список полей может конфигурироваться, что задачу не облегчает. Но к счастью вместе с IIS 5.0 в составе прочих компонентов, поставляется компонент MSWC.IISLog, который предназначен для получения данных из log-файлов и предоставляет для этой цели интерфейс ILogScripting. Находится он в файле %windir%system32inetsrvlogscrpt.dll. С помощью этого интерфейса можно читать данные из log-файла, записывать прочтенные данные в другой файл. Перед тем как начать работу с какими-либо log-файлом, его нужно открыть. Дляэтогослужитметод OpenLogFile: HRESULT OpenLogFile( [in] BSTR szLogFileName, [in] IOMode Mode, [in] BSTR szServiceName, [in] long iServiceInstance, [in] BSTR szOutputLogFileFormat), где в параметре szLogFileName задается полный путь к файлу; параметр Mode может принимать следующие значения: ForReading - файл будет открыт для чтения ForWriting - файл будет открыт для записи; в параметре szServiceName задается название службы, которой был создан данный файл (например "W3SVC"); парметр iServiceInstance указывает номер экземпляра сервера данной службы (напр. 1); в параметре szOutputLogFileFormat задается название формата, в котором будут читаться или записываться данные (например "W3C"). Если метод выполнился успешно то возвращается 0. Для чтения данных из файла служит метод ReadLogRecord: HRESULT ReadLogRecord(), который читает строку из текущей файловой позиции и перемещает позиционер файла дальше. Мы можем получить эти данные в виде значений конкретных полей с помощью множества методов, которые возвращают эти значения:
Всеэтиметодыимеютодинформат: HRESULT get_MethodName(VARIANT *pValue). В параметре pValue будет возвращено интересующее нас значение. Если значение запрашиваемого параметра равно "-", то тип pValue будет VT_EMPTY. Если же по каким-то причинам параметр не будет найден в log-файле (напр. параметр отключен, или текущая строка - незначащая), то тип pValue будет VT_NULL. Для того, чтобы мы сильно не увлеклись существует метод AtEndOfLog, который подобно привычному feof возвращает (или не возвращает :)) признак достижения конца файла и выглядит приблизительно так: HRESULT AtEndOfLog([out, retval] VARIANT_BOOL* pfEndOfRead) В параметре pfEndOfRead, собственно, и возвращается интересующий нас признак, что позволяет нам все таки когда-нибудь завершить обработку log-файла. Помимо всего этого имеется еще метод WriteLogRecord, который позволяет записывать данные, полученные из одного log-файла в другой. Формат его следующий: HRESULT WriteLogRecord([in] ILogScripting* pILogScripting), где pILogScripting - это указатель на экземпляр ILogScripting, в котором содержатся прочитанные данные. Этот метод похож на ReadLogRecord тем, что записывает в файл одну строку (напомню, что ReadLogRecord читает одну строку). Для закрытия открытых файлов служит метод CloseLogFiles: HRESULT CloseLogFiles([in] IOMode Mode), в котором параметр Mode может принимать следующие значения: ForReading - будут закрыты файлы, открытые для чтения ForWriting - будут закрыты файлы, открытые для записи AllOpenFiles - будут закрыты все открытые файлы Чтобы доступиться к компоненту MSWC.IISLog из C++ надо иметь .h файл, описывающий интерфейс ILogScripting. Сделать его нам поможет утилита OLEViewer, которая входит в состав Visual Studio. В меню "File" этой утилиты выберем пункт "View TypeLib" и укажем файл logscrpt.dll (естественно полный путь к нему). В новом окне откроется библиотека типов нашего объекта, которую мы сохраним в качестве .idl файла. Для этого в меню "File" выберем пункт "Save as", укажем тип файла "idl", и сохраним его в некое место (например туда, где находится проект), к примеру, назвав его "logscrpt.idl". Все бы хорошо, да только в новоиспеченном файле придется сделать косметические изменения. Во-первых в самое начало файла надо вставить следующие строчки: cpp_quote("DEFINE_GUID(CLSID_LogScripting, 0x26B9ED02, 0xA3D8, 0x11D1, 0x8B, 0x9C, 0x08, 0x00, 0x09, 0xDC, 0xC2, 0xFA);") cpp_quote("DEFINE_GUID(IID_ILogScripting, 0x26B9ECFF, 0xA3D8, 0x11D1, 0x8B, 0x9C, 0x08, 0x00, 0x09, 0xDC, 0xC2, 0xFA);") Во-вторых строчки typedef enum { ForReading = 1, ForWriting = 2, AllOpenFiles = 32 } IOMode; надо перенести так, чтобы они находились до определения ILogScripting интерфейса. Теперь осталось только сгенерировать файл logscrpt.h с помощью команды midl.exe logscrpt.idl /h logscrpt.h (проверьте путь к компилятору midl). В заключение приведу пример программы работы с интерфейсом, которая получает в качестве параметров командной строки путь к log-файлу, название службы, название формата файла, номер экземпляра сервера и выдает на экран список всех URL адресов, к которым были зафиксированы обращения в этом файле. Вот пример вызова этой программы: logging.exe d:logsw3svc2ex01060515.log W3SVC W3C 2 #include #include #include #include #include "logscrpt.h" #define SOME_ERROR(lpszErrorText, nErrorNum) printf("%s: %X ", lpszErrorText, nErrorNum); throw nErrorNum; int main(int argc, char *argv[]) { HRESULT hres; VARIANT vParam; short nEndOfFile; _bstr_t bstrLogFile; _bstr_t bstrServiceName; _bstr_t bstrLogFormat; long nServerInstance; _bstr_t bstrUriStem; // проверка наличия параметров if (argc < 5) { printf("Usage: %s LogFileName ServiceNa me LogFormatName ServerInstance ", argv[0]); return 0; } // получаем параметры из коммандной строки try { bstrLogFile = argv[1]; bstrServiceName = argv[2]; bstrLogFormat = argv[3]; if (!(nServerInstance = atol(argv[4]))) // экземплярсерверанеможетбыть 0 nServerInstance = 1; } catch (...) { printf("Something wrong in parameters! "); return 0; } // это будет ссылка на интерфейс ILogScripting *pLogScripting = NULL; try { // инициализируем COM if (!SUCCEEDED(hres = CoInitialize(NULL))) { SOME_ERROR("CoInitialize error", hres); } // теперьсоздадимэкзепляринтерфейса if (!SUCCEEDED(hres = CoCreateInstance(CLSID_LogScripting, NULL, CLSCTX_ALL, IID_ILogScripting, (void **)&pLogScripting))) { SOME_ERROR("CoCreateInstance error", hres); } // открываем log-файл bstrLogFile для чтения, указывая, что этот // файл относится к первому экземляру сервера службы W3SVC, а // // форматунего W3C if (!SUCCEEDED(hres = pLogScripting-OpenLogFile(BSTR(bstrLogFile), ForReading, BSTR(bstrServiceName), 1, BSTR(bstrLogFormat)))) { SOME_ERROR("OpenLogFile error", hres); } // теперь можно приступить к анализу содержимого файла for ( ;; ) { // проверим на достижение конца файла if (!SUCCEEDED(hres = pLogScripting-AtEndOfLog(&nEndOfFile))) { SOME_ERROR("AtEndOfLog error", hres); } if (nEndOfFile) // счастливо выходим break; // читаемследующуюзаписьфайла if (!SUCCEEDED(hres = pLogScripting-ReadLogRecord())) { SOME_ERROR("ReadLogRecord error", hres); } // получаем из нее параметр адрес URL if (!SUCCEEDED(hres = pLogScripting-get_URIStem(&vParam))) { SOME_ERROR("ReadLogRecord error", hres); } if (vParam.vt == VT_BSTR) { // если параметр не пуст распечатаем его на экране bstrUriStem = vParam.bstrVal; printf("Uri-stem: %s ", LPSTR(bstrUriStem)); } } // закрываемфайл if (!SUCCEEDED(hres = pLogScripting-CloseLogFiles(ForReading))) { SOME_ERROR("CloseLogFiles error", hres); } } catch (...) {} // последние действия по деинициализации if (pLogScripting != NULL) pLogScripting-Release(); CoUninitialize(); return hres; } Dima Mukalov |