Logging Server Statistics
Logging and parsing server statistics can provide you with a lot of valuable information about your server configuration and your user base. Parsing the data in your log files can help you determine exactly what your users are streaming and when they are streaming it. Based on the statistical trends you find, you may need to alter your server configuration to better accommodate your client connections. By using the logs created by the WMS Client Logging Plug-in, you can more effectively administer your Windows Media Server. You can also create a custom logging plug-in to meet specific needs. For more information, see Creating Logging Plug-ins.
The following Visual Basic .NET, C#, and C++ examples illustrate how to take advantage of the log files created by the WMS Client Logging plug-in by parsing and storing the data for analysis.
Visual Basic .NET Example
Imports System.IO
Imports System.Runtime.InteropServices
' Declare variables.
Dim strLogLine As String
Dim strFieldNames() As String
Dim strLogValues(,) As String
Dim iFieldCount As Integer
Dim iLineCount As Integer
Dim iStart As Integer
Dim iEnd As Integer
Dim i As Integer
Dim sr As StreamReader
Try
' Open the log file for parsing.
sr = New StreamReader("c:\\Windows\\System32\\LogFiles\\WMS\\Test1\\WMS_Test.log")
' Read a line at a time from the log file and process it.
strLogLine = sr.ReadLine()
Do While (strLogLine <> "")
' If the field names have been processed,
' then this line can be read in as log data.
If iFieldCount > 0 Then
iLineCount = iLineCount + 1
' Dynamically allocate memory for a new log line.
ReDim Preserve strLogValues(iFieldCount, iLineCount)
' Store the log data from each field.
iStart = 1
For i = 1 To iFieldCount
iEnd = InStr(iStart + 1, strLogLine, " ", vbTextCompare)
If iEnd = 0 Then
strLogValues(i, iLineCount) = Mid(strLogLine, iStart + 1)
Else
strLogValues(i, iLineCount) = Mid(strLogLine, _
iStart + 1, _
iEnd - iStart - 1)
End If
iStart = iEnd
Next
End If
' Process all the field names in the log.
If InStr(1, strLogLine, "#Fields: ", vbTextCompare) <> 0 Then
iFieldCount = 1
iStart = InStr(1, strLogLine, " ", vbTextCompare)
Do While iStart <> 0
iEnd = InStr(iStart + 1, strLogLine, " ", vbTextCompare)
' Dynamically allocate memory for a new field name.
ReDim Preserve strFieldNames(iFieldCount)
' Store each field name.
If iEnd = 0 Then
strFieldNames(iFieldCount) = Mid(strLogLine, iStart + 1)
Else
strFieldNames(iFieldCount) = Mid(strLogLine, _
iStart + 1, _
iEnd - iStart - 1)
iFieldCount = iFieldCount + 1
End If
iStart = iEnd
Loop
End If
strLogLine = sr.ReadLine()
Loop
' Close the log file.
sr.Close()
Catch errCom As COMException
' TODO: Handle COM exceptions.
Catch err As Exception
' TODO: Exception handler goes here.
Finally
' TODO: Clean-up code goes here.
End Try
C# Example
using System.IO;
using System.Runtime.InteropServices;
// Declare variables
string strLogLine = "";
string[] strFieldNames = new string[1];
string[] strFieldValues = new string[1];
StreamReader sr;
try
{
// Open the log file for parsing.
sr = new StreamReader("c:\\Windows\\System32\\LogFiles\\WMS\\Test1\\WMS_Test.log");
// Read a line at a time from the
// log file and process the last two lines.
// (The last line contains the values; the prior line
// contains the names.)
strLogLine = sr.ReadLine();
while (strLogLine != null)
{
if (strLogLine.IndexOf("#Fields") != -1) // extract field names and values
{
strFieldNames = strLogLine.Split(' ');
strLogLine = sr.ReadLine();
strFieldValues = strLogLine.Split(' ');
}
strLogLine = sr.ReadLine();
}
// Close the intput file.
sr.Close();
}
catch (COMException comExc)
{
// TODO: Handle COM exceptions.
}
catch (Exception exc)
{
// TODO: Exception handler goes here.
}
finally
{
// TODO: Clean-up code goes here.
}
C++ Example
#define _UNICODE // Enables Unicode character handling for log
#define UNICODE // files using Unicode instead of ANSI encoding.
#include <windows.h>
#include <stdio.h>
#include <tchar.h> // Includes generic text handling functions.
// Declare variables.
FILE *pLogFile;
TCHAR ptcLogLine[MAX_LINE];
TCHAR ptcFieldNames[MAX_FIELDS][MAX_FIELDLENGTH];
TCHAR ptcLogValues[MAX_LOGLINES][MAX_FIELDS][MAX_FIELDLENGTH];
TCHAR *ptcToken;
TCHAR *ptcContext = NULL;
UINT uiIndex;
UINT uiInput;
UINT uiLineCount = 0;
UINT uiFieldCount = 0;
// Open the log file for parsing.
pLogFile = _tfopen(TEXT("c:\\LogFiles\\WMS_Unicode.log"), TEXT("rb"));
// Read a line at a time from the log file and process it.
while(_fgetts(ptcLogLine, MAX_LINE, pLogFile) != NULL)
{
// Remove the trailing newline character from the log line.
ptcLogLine[_tcsclen(ptcLogLine)-1] = '\0';
// If the field names have been processed,
// then this line can be read in as log data.
if(uiFieldCount > 0)
{
uiIndex = 0;
uiLineCount++;
ptcToken = _tcstok_s(ptcLogLine, TEXT(" "), &ptcContext);
// Store the log data from each field.
while(ptcToken != NULL)
{
uiIndex++;
_tcsncpy_s(ptcLogValues[uiLineCount - 1][uiIndex - 1],
MAX_FIELDLENGTH, ptcToken, _TRUNCATE);
ptcToken = _tcstok_s(NULL, TEXT(" "), &ptcContext);
;
}
}
// Process all the field names in the log.
if(_tcsstr(ptcLogLine, TEXT("#Fields:")) != NULL)
{
ptcToken = _tcstok_s(NULL, TEXT(" "), &ptcContext);
// Store each field name.
while(ptcToken != NULL)
{
uiFieldCount++;
_tcsncpy_s(ptcFieldNames[uiFieldCount - 1], MAX_FIELDLENGTH,
ptcToken, _TRUNCATE);
ptcToken = _tcstok_s(NULL, TEXT(" "), &ptcContext);
}
}
}
// Close the log file.
fclose(pLogFile);
EXIT:
// TODO: Release temporary COM objects and uninitialize COM.