HOWTO: Get Field Data for Custom Logging with ISAPI Filter


I’m trying to write a Filter that handles writing a W3C-compliant log file based on a special set of criteria.  I have found most of the needed information in GetServerVariables(), but I still need the following things:

sc-status: The status code returned by the server on the request (i.e. 200 if the HTTP request was OK)

sc-substatus: Substatus code, it’s an entry in the current IIS log files and I’d like to keep it

sc-win32-status: Appears to always be 0, but I’ll keep it if I can.

sc-bytes: The number of bytes sent back to the client as the response.

time-taken: The amount of time it took IIS internally to process and complete the request.

If anyone can help me with the necessary calls to get these values, that would be wonderful.  They are values in the normal IIS log files when W3C is selected, so I feel like they must be available.



You can do it the EASY way or the HARD way. 🙂 I’ll provide you the info; you pick.

Easy Way

The info you want can be found in the HTTP_FILTER_LOG structure available in the SF_NOTIFY_LOG ISAPI Filter event.

typedef struct _HTTP_FILTER_LOG
const CHAR * pszClientHostName;
const CHAR * pszClientUserName;
const CHAR * pszServerName;
const CHAR * pszOperation;
const CHAR * pszTarget;
const CHAR * pszParameters;

DWORD dwHttpStatus;
DWORD dwWin32Status;

DWORD dwBytesSent;
DWORD dwBytesRecvd;
DWORD msTimeForProcessing;


The SF_NOTIFY_LOG event happens right before IIS is about to write the log entry for that request. The members of HTTP_FILTER_LOG are read/write, so it should be trivial for you to use it for custom logging purposes.

What are the benefits of using HTTP_FILTER_LOG?

  1. You do not need to call GetServerVariable() and [re]-allocate a buffer (see this blog entry for an example)
  2. You can even alter what IIS will log by changing the fields of this structure (see this blog entry for an example) – so you can modify pszParameters, have IIS keep the merged log files of all your subdomains (for analysis purposes), and still know which request went to which subdomain

The only thing that is missing is sc-substatus, and it cannot be retrieved in ISAPI Filter.

Hard Way

If you insist on doing it the hard way:

  • sc-status can be obtained from SF_NOTIFY_SEND_RESPONSE, in the HTTP_FILTER_SEND_RESPONSE.HttpStatus member. This only works for structured responses… for raw responses, you have to buffer and parse SF_NOTIFY_SEND_RAW_DATA.
  • sc-substatus and sc-win32-status:

    The only way on IIS6 to get sc-substatus and sc-win32-status for the response is in the async completion function of an HSE_REQ_EXEC_URL ServerSupportFunction call by calling HSE_REQ_GET_EXEC_URL_STATUS.

    Nowhere else in ISAPI Filter/Extension API do you have access to that value, even though we added sc-substatus in IIS6, because we would break binary compatibility by changing existing structures where it logically belongs:

    • You can’t read/set it in ISAPI Filter
    • You can’t set it in ISAPI Extension
    • You can read it in ISAPI Extension in async completion function HSE_REQ_EXEC_URL

  • sc-bytes – listen on SF_NOTIFY_SEND_RAW_DATA and track HTTP_FILTER_RAW_DATA.cbInData to count number of bytes transferred. Hard part is figuring out how to do this on a per-request basis because pFilterContext is per-connection.
  • time-taken – Set timer between SF_NOTIFY_READ_RAW_DATA and SF_NOTIFY_END_OF_NET_SESSION. This is not compatible with IIS6 Worker Process Isolation Mode.


Comments (11)

  1. Jacob Arthur says:

    Ok, so question about that.  You said that I should be able to get everything I need out of parameters, but I think I may not be understanding that exactly as you meant it.  I need user agent and referer for example;  am I correct in thinking that data is not in pszParameters?  I output-ed pszParameters and it looks like garbage to me on the request.  To get user_agent and referer I will still have to call GetServerVariables correct?

  2. David.Wang says:

    Jacob – I do not think I ever said or implied "you can get everything you need out of parameters". If that was your take-away, my apologies.

    The original question asked: "where to get sc-status, sc-substatus, sc-win32-status, sc-bytes, and time-taken?", so that was what I showed.

    The NEW question is "where to get User-Agent and Referer?", and I suggest either:

    1. Call GetHeader from SF_NOTIFY_PREPROC_HEADERS and storing it in pFilterContext ( Example code: )

    2. Call GetServerVariable in SF_NOTIFY_LOG


  3. Jacob Arthur says:

    Ok, I thought that was what you meant, I just wanted to make sure that information wasn’t somehow available out of the parameters field with some processing.  Thanks for all of your help, I think I have everything I need to know.  I’ll let you know how it turns out.


  4. David – Apologies if this is addressed elsewhere but I didn’t see it.

    Our web server is protected by SiteMinder.  IIS 6.0 is running anonymous and SM handles the authentication.  I’m trying to create an add’l ISAPI that does an extra lookup in Active Directory to check if the user is a member of a particular group.

    I started with the AuthFilter example and am trying to use GetServerVariable to retrieve the user’s id, but I’m finding that REMOTE_USER, LOGON_USER, etc are all blank.  Is there a way to get the user’s id if IIS is running anonymous?


  5. David.Wang says:

    Bret – SiteMinder implements custom authentication and forces IIS to run with anonymous authentication so that it can do its proprietary actions. This means that AUTH_USER, REMOTE_USER, LOGON_USER, AUTH_TYPE, etc are all anonymous from IIS perspective.

    You will have to contact Netegrity support to determine how to integrate with their custom authentication solution. I believe SiteMinder uses a custom request header which can be decoded to retrieve the SiteMinder username – which you can retrieve via ISAPI Filter. See:


  6. says:

    We have a web application that creates PDF’s.   We are seeing in our IIS logs records where the sc-win32-status equals 64 but the sc-status equals 200.    The PDF’s are NOT being created.   I have seen a number of postings that appear to be same as this issue but not definitive answers.    Can someone explain what is going on?

  7. newro says:


    I have a question about custom Logging data.

    A client requests a file (1MB) and IIS send the file.

    If some error occurs, then sending file would not be completed.

    At this time, IIS has log

  8. David.Wang says:

    newro – Logging has to happen regardless if the request succeeds or fails. Use the dwWin32Status and dwHttpStatus fields to distinguish between successful and failing requests.


  9. David.Wang says:

    john.corbett – Many things can result in that status code. One common cause is the client disconnecting, such as a user hitting F5 to refresh because your web application took too long to create the PDF.


  10. Mark Schall says:

    Is there an equivalent way to get the "bytes sent" using the managed modules?