בחלקו הראשון של המאמר, כתבתי על הדרך להעביר את קבצי הלוג אל טבלאות ה SQL SERVER, דיברתי שם על בניית תוכנית קטנה ב VB ועל הרצת התוכנית כל יום בצורה ידנית.
הוספתי גם שבעיקרון אפשר ליצור אובייקט ACTIVEX.DLL ואתו ע"י TASK יומי של ה SQL SERVER לבצע את העברת הקובץ אל בסיס הנתונים.
אחרי מספר ימים שעבדתי עם התוכנית שכתבתי לעצמי, הגעתי למסקנה שלא מתחשק לי להריץ את זה כל יום בצורה ידנית.
אני רוצה לבוא בבוקר, לפתוח את האתר בו מצויות הסטטיסטיקות שלי ומייד לראות את כל מה שקרה אמש על האתר שלי, בלי להריץ קודם כל תוכניות כל שהן.
נוסף על כך, אין לי חשק להריץ את התוכנית מספר פעמים על כל הקבצים שהחמצתי, היות והייתי בחו"ל או בחופש ולא לייד המחשב בו נמצאת, אפליקציית ה VB שמעבירה את הקבצים מספריית ה LOGFILES בשרת, לטבלת ה LOGFILES בשרת.
שלב א: הפיכת תוכנית ה STANDART.EXE ל DLL.
פתחתי ב VB פרוייקט חדש ACTIVEX.DLL שיניתי את שם הפרוייקט ע"י בחירה ב PROJECT | PROPERTIES ל CreateLogTable. את שם דף ה CLASS שנפתח שיניתי ל clsLofFiles. (כמו במאמר הקודם, ההמלצה שלי היא להריץ פעם ראשונה DTS ידני ולשמור את הקובץ שהוא מייצר)
יצרתי REFFERENCE לאובייקט Microsoft DTSPackage Object Library
הגדרתי משתנים בתחילת ה CLASS
Public goPackageOld As New DTS.Package
Public goPackage As DTS.Package2
Dim File2DTS As String, File2DTS_Name As String
והגדרתי פונקציה הכוללת פרמטרים
Function CreateTheFile(name1 As String, name2 As String, serverName As String)
היות ורציתי להשתמש ממש באותם הקודים בתוכנית הקודמת שעשיתי ולא לשנות בה הרבה, העברתי את הנתונים מתוך הפרמטרים למשתנים הגלובאלים אותם הגדרתי קודם.
File2DTS = name1
File2DTS_Name = name2
כאשר File2DTS הנו השם והמסלול של הקובץ אותו אני רוצה להעביר לבסיס הנתונים לדוגמא: C:WINNTsystem32LogFilesW3SVC1ex010825.log
וה File2DTS_Name הנו שם הטבלה החדשה אותה אני רוצה להקים בבסיס הנתונים.
את הפרמטר של השרת עליו נמצא בסיס הנתונים לא הייתי צריך להעביר למשתנה גלובאלי שכן הפניות לפרמטר הזה נעשות רק בפונקציה עצמה, בעוד שהפניות לערכים של המסלול ושם הטבלה נמצאות גם ב סאב רוטינות שמבצעות את ה DTS.
נוסף על כך בסוף הפונקציה הוספתי החזרת ערך TRUE במידה והפונקציה הצליחה.
CreateTheFile = True
כל מה שהצטרכתי לעשות זה לשנות את שם השרת בתוכנית הקודמת מקוד קשיח למשתנה serverName ובעצם האובייקט היה מוכן.
קימפלתי את האובייקט, התקנתי אותו ב COM+ על השרת, והייתי מוכן לשלב הבא.
שלב ב: יצירת תוכנית ASP שתייצר טבלאות של קבצי הלוג בצורה ידנית.
נכון, המטרה הייתה לעשות את זה אוטומטי לחלוטין, אבל מה יקרה אם ב 5:00 בבוקר הסרוור לא יפעל ולא יבצע את הTASK היומי להמרת קבצי הלוג לטבלאות, ואני בכלל אהיה בפריס, ודרך האינטרנט קפה שאליו אלך, כדי לראות מה קורה בשרת שלי לא אוכל להפעיל שום תוכנית שתעביר לי את קבצי הלוג לבסיס הנתונים ולא אדע כמה גולשים ביקרו אצלי באתר, לכן החלטתי להשאיר את אופציית ההעברה הידנית פתוחה למקרי חירום. ולהרחיב אותה למצב שאוכל לבצע אותה מכל מחשב בעולם המחובר לאינטרנט ויש עליו בראוזר.
<%
קבעתי קבוע גלובאלי למיקום קבצי הלוג, כמובן שהייתי
יכול להכניס גם את הקלדת מיקום קבצי הלוג לתוך התוכנית.
Const mypath="C:WINNTsystem32LogFilesW3SVC1"
בניתי תוכנית קטנה שמשתמשת ב filesystemobject לבניית קומבו בוקס עם רשימת כל קבצי הלוג שנמצאים בספריה
Dim FileSystem, folder, filecollection
Set filesystem = server.CreateObject("Scripting.FileSystemObject")
Set folder = filesystem.GetFolder(mypath(
Set filecollection = folder.Files
בניתי FORM עם רשימת הקבצים וכפתור לביצוע העברת הקובץ הנבחר
%>
כאשר ה SUBMIT מתבצע לאחר שנבחר ערך בקומבו בוקס התוכנית הבאה מבצעת את העברת הקבצים לטבלה.
<%
if request("selFileList") <> "" then
תחילה מתבצעות פעולות על מחרוזת בכדי להעביר את הפרמטרים הנכונים לאובייקט
retVal=cstr(request("selFileList"))
fileloc="C:WINNTsystem32LogFilesW3SVC10" & retVal
tablename=left(retVal,len(retVal)-4(
קריאה לאובייקט CreateLogTable ולקלאס clsDTSLogfile הנמצא בתוכו אותו בניתי בשלב א
Set getMakeTable = server.CreateObject("CrateLogTable.clsDTSLogfile")
קריאה לפונקציה CreateTheFile
כולל הפרמטרים, שם קובץ הלוג והמסלול, שם הטבלה ושם השרת עליו נמצא בסיס הנתונים
xxx = getMakeTable.CreateTheFile(cstr(fileloc),cstr(tablename), cstr("Boo"))
הודעה על ביצוע מוצלח של העברת הקובץ
Response.Write "file " & request("selFileList") & " transferd succesfuly"
end if
%>
שלב ג: בניית STORED PROCEDURE שיבצע את העברת הקבצים.
כדי לבצע את העברת הקבצים בצורה אוטומטית הייתי זקוק לתוכנית אחרת שתדע להריץ את ה DLL שבניתי באופן קבוע כל יום ב 5.00 בבוקר, יש מספר דרכים לעשות את זה, אני בחרתי להשתמש ב JOB MANEGER של ה SQL Server שבתוכו אפשר לקבוע שפעולה מסוימת תתבצע כל יום, פעם בשבוע, פעם בשנה, או מתי שרוצים, בשרת.
הכוונה בפעולה מסוימת זה הרצת STORED PROCEDURE שיריץ את האובייקט לבניית ה DTS ויבנה לי טבלה שמכילה את קובץ הלוג של היום הקודם.
נוסף על כך, חשבתי, היות וזה Stored Procedure אני כבר יכול לנצל אותו לעוד כמה דברים של טיפול בטבלה לאחר שנטענה, כדוגמא הרחקת כל השורות ב LOGFILE שאינם מכילים דאטה אמיתי, שורות כמו 4 השורות הראשונות בקובץ הלוג שלפעמיים חוזרות על עצמן באמצע קובץ הלוג, למשל, כאשר נעשה אתחול לשרת, מערכת הלוגים ממשיכה את הלוג הקיים לאותו יום ומוסיפה שוב את 4 השורות הראשונות.
הגדרת הפרוצדורה והמשתנים שיועברו, כאשר כפי שתראו בהמשך אני אעביר לפרוצדורה רק את המסלול בו נמצאים קבצי הלוג + שם השרת עליו נמצא ה SQL.
CREATE PROCEDURE sp_Transfer_Log_Files
@Name1 varchar(255) , @ServerName varchar(255)
AS
הגדרת משתנים לעבודה בתוך הפרוצדורה
DECLARE @Object int
DECLARE @Hresult int
DECLARE @TransferDone bit
DECLARE @ErrorSource varchar (255)
DECLARE @ErrorDesc varchar (255)
DECLARE @StrSql varchar (2000)
DECLARE @strYesterday1 char(10)
DECLARE @strYesterday2 char(8)
DECLARE @strmonth char (2)
DECLARE @strYear char (2)
DECLARE @strDay char (2)
DECLARE @strPath varchar (255)
קביעת המשתנה @strYesterday1 עם התאריך של היום הקודם
set @strYesterday1 = convert(char(10),DATEADD(day, -1, GETDATE()),103)
הוצאת היום החודש והשנה מתוך המשתנה 1@strYesterday , במידה והיום או החודש קטנים מ 10 הוספת מוביל 0 לפני
set @strmonth = MONTH(convert(datetime,@strYesterday1,103))
if @strmonth < 10
BEGIN
set @strmonth = 0 + @strmonth
END
set @strDay = DAY(convert(datetime,@strYesterday1,103))
if @strDay < 10
BEGIN
set @strDay = 0 + @strDay
END
set @strYear = RIGHT(@strYesterday1,2)
יצירת המשתנה @strYesterday2 שמכיל בתוכו את שם קובץ הלוג מאתמול
set @strYesterday2 = ex + @strYear + @strmonth + @strDay
יצירת המשתנה @strPath המכיל את המסלול לקובץ + שם הקובץ + הסיומת .log
set @strPath = @name1 + @strYesterday2 + .log
בתוך SQL SERVER ישנם מספר פרוצדורות שמורות הנקראות Extended Stored Procedure פרוצדורות אלו נמצאות בבסיס הנתונים MASTER ויש להן שימושים רבים, אנחנו נשתמש בתוכנית הזאת בשלוש פרוצדורות חיצוניות
sp_OACreate משמש ליצירת אובייקטים, מקביל ל server.createObject ב ASP
sp_OAMethod משמש להעברת פרמטרים לאובייק שנוצר ע"י sp_OACreate
sp_OADestroy משמש לסגירת האובייקט, מקביל ל set obj=Nothing ב ASP
המשתנה @Hresult יחזיר פרמטרים האם התבצעה הפעולה
--Create the object
EXEC @Hresult=sp_OACreate CrateLogTable.clsDTSLogfile, @Object OUT
--Call the objects property and return the value
EXEC @Hresult=sp_OAMethod @Object,CreateTheFile,@TransferDone OUT,_
@strPath,@strYesterday2,@ServerName
--Destroy the object
EXEC @Hresult=sp_OADestroy @Object
פרוצדורה חיצונית נוספת הנה ה sp_OAGetErrorInfo המטפלת בהודעות ERROR, אם המשתנה @Hresult קיבל ערך השונה מ 0 התבצעה שגיאה באחת משלושת הפרוצדורות הקודמות, שימוש בפרוצדורה sp_OAGetErrorInfo יאפשר לנו לקבל את תיאור השגיאה
IF @Hresult <> 0
BEGIN
EXEC sp_OAGetErrorInfo @Object, @ErrorSource OUT, @ErrorDesc OUT
PRINT Error Occurred Calling Object: + @ErrorSource + + @ErrorDesc
RETURN
END
כאשר האובייקט מסיים את פעולתו כזכור לכם משלב א הוא מחזיר ערך TRUE את הערך הזה מכניסים המשתנה @TransferDone ואפשר בעצם לדעת עם הפעולה של העברת הקובץ לתוך בסיס הנתונים התבצעה.
IF @TransferDone = 1
BEGIN
PRINT The Logfile + @strYesterday2 + was transfer correctly.
END
ELSE
BEGIN
PRINT The Logfile + @strYesterday2 + was transfer incorrectly.
END
מכאן והילך אפשר לבצע כל מיני פעולות על הטבלה החדשה שנוצרה בבסיס הנתונים
אחת הפעולות היא לסלק את כל הרשומות שאינן מכילות דאטה על המבקרים ונוצרו מהכותרות המוכנסות לתוך קובץ הלוג. שורות אלו יכילו בעמודה הראשונה Col001 את הערכים #Software, #Version, #Date, #Fields בעזרת משפט ה SQL הבא נוכל לנקות את הטבלה מהרשומות הללו.
set @StrSql =DELETE FROM +@strYesterday2+ WHERE Col001 =#Software:_
OR Col001 = #Version:
OR Col001 = #Date: OR Col001 =#Fields:
exec (@StrSql)
כמובן שאפשר למצוא עוד דוגמאות למה שאפשר לתקן בנתונים. דוגמא אחת, נגיד שלא מעניין אותכם כל הגישות לקבצי הגראפיקה, אז אפשר לעשות DELETE לכל הרשומות שמכילות את המילה ‘%.gif או %.jpg ועוד רעיונות כמיטב מוחיכם הקודח.
שלב ד: בניית TASK להפעלת הפרוצדורה
השלב האחרון הנו בניית התהליך שיריץ כל לילה את הפרוצדורה השמורה sp_Transfer_Log_Files שתריץ את הקלאס csDTSLogfile שנמצא בתוך הקומפוננט CrateLogTable בשעה 5:00 בבוקר ויעביר את קובץ הלוג לתוך טבלה חדשה בבסיס הנתונים.
לשם כך נפנה ל JOB MANEGER של השרת
נפתח את העץ MANEGMENT בתוך ה ENTERPRISE MANEGER של ה SQL SERVER ונבחר ב SQL Server Agent. בדרך כלל ה AGENT הנו במצב של תרדמה, כלומר אינו מופעל, יש להפעיל אותו, וגם לדאוג לכך שכל פעם שהשרת עולה גם הוא יעלה. דרך ה SERVICES ב CONTROL PANEL יש להפוך את ה SQLSERVERAGENT מהפעלה ידנית לאוטומטית.
תחת ה SQL Server Agent נבחר JOB חדש, בלשונית GENERAL ניתן לו שם חדש, בלשונית STEPS נוסיף צעד חדש שיכיל את המשפט:
excute sp_Transfer_Log_Files C:WINNTsystem32LogFilesW3SVC1, MyServer
כאשר הפרמטר הראשון הנו המסלול לקובצי הלוג, והפרמטר השני הוא שם שרת ה SQL שעליו נמצא בסיס הנתונים.
בלשונית SCHUDULE נקבע כי אנחנו רוצים שהJOB יתבצע כל יום ב 5:00 בבוקר, נשמור ונסגור. וממחר ב 5:00 בבוקר יש לנו כל יום את קובץ הלוג מוגש על מגש למערכת הסטטיסטיקות שבנינו.
את ביצוע בניית ה JOB אפשר לבצע גם ע"י SQL סקריפט שנראה כך:
BEGIN TRANSACTION
DECLARE @JobID BINARY(16)
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
IF (SELECT COUNT(*) FROM msdb.dbo.syscategories WHERE name = NWeb Assistant) < 1
EXECUTE msdb.dbo.sp_add_category @name = NWeb Assistant
-- Delete the job with the same name (if it exists)
SELECT @JobID = job_id
FROM msdb.dbo.sysjobs
WHERE (name = NYesterday_logFile)
IF (@JobID IS NOT NULL)
BEGIN
-- Check if the job is a multi-server job
IF (EXISTS (SELECT *
FROM msdb.dbo.sysjobservers
WHERE (job_id = @JobID) AND (server_id <> 0)))
BEGIN
-- There is, so abort the script
RAISERROR (NUnable to import job Yesterday_logFile since there is already a
multi-server job with this name., 16, 1)
GOTO QuitWithRollback
END
ELSE
-- Delete the [local] job
EXECUTE msdb.dbo.sp_delete_job @job_name = NYesterday_logFile
SELECT @JobID = NULL
END
BEGIN
-- Add the job
EXECUTE @ReturnCode = msdb.dbo.sp_add_job @job_id = @JobID OUTPUT ,
@job_name = NYesterday_logFile, @owner_login_name = NBOOAdministrator,
@description = NNo description available., @category_name = NWeb Assistant,
@enabled = 1, @notify_level_email = 0, @notify_level_page = 0,
@notify_level_netsend = 0, @notify_level_eventlog = 2, @delete_level= 0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
-- Add the job steps
EXECUTE @ReturnCode = msdb.dbo.sp_add_jobstep @job_id = @JobID, @step_id = 1,
@step_name = NCreate_Log_Table,
@command = Nexecute sp_Transfer_Log_Files C:WINNTsystem32LogFilesW3SVC10,
Boo, @database_name = NLogFiles, @server = N,
@database_user_name = N, @subsystem = NTSQL, @cmdexec_success_code = 0,
@flags = 0, @retry_attempts = 0, @retry_interval = 1,
@output_file_name = N, @on_success_step_id = 0, @on_success_action = 1,
@on_fail_step_id = 0, @on_fail_action = 2
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXECUTE @ReturnCode = msdb.dbo.sp_update_job @job_id = @JobID, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
-- Add the job schedules
EXECUTE @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id = @JobID,
@name = NCreate_Log_Table, @enabled = 1, @freq_type = 4,
@active_start_date = 20011001, @active_start_time = 50000, @freq_interval = 1,
@freq_subday_type = 1, @freq_subday_interval = 0, @freq_relative_interval = 0,
@freq_recurrence_factor = 0, @active_end_date = 99991231, @active_end_time = 235959
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
-- Add the Target Servers
EXECUTE @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @JobID, @server_name = N(local)
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
END
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
בהצלחה ו Happy Programming
|