Web服务跟踪/日志

6

我有一组Web服务,想要添加一个跟踪层。 由于数量众多,我不想修改每个Web服务。 我希望在进入Web服务时记录日志:Web服务名称和参数。

最好的方法是什么?

P.S. 我使用asp.net和C#。

编辑: 我只想对Web服务进行包装,每个Web服务开头都有log(..)。


“我不想修改每个 Web 服务,因为我有很多。” - 可以使用 AOP,否则我认为你必须这样做。... - Mitch Wheat
2
你可以使用服务器访问日志。 - please delete me
请参阅 SoapExtension 类的 MSDN 文档。其中有一个记录示例。 - John Saunders
这是面向方面的编程...他所说的是,你可以插入一个DI(依赖注入)容器,比如Unity、StructureMap或其他,并在你的代码中添加所谓的拦截器。这是一种相当常见的方法,但我不会说它是最容易做到的。这里有一个例子 - http://hmadrigal.wordpress.com/2010/12/25/aspect-oriented-programming-and-interceptor-design-pattern-with-unity-2/ - phillip
7个回答

6
一种常见的方法是注入SOAP扩展程序。从那里,您可以拦截每个原始SOAP请求/响应数据包。示例展示了如何实现它,解释了它的工作原理以及如何配置它。
示例:

http://msdn.microsoft.com/en-us/library/system.web.services.protocols.soapextension.aspx

解释:

http://msdn.microsoft.com/en-us/library/esw638yk(vs.71).aspx

配置:

http://msdn.microsoft.com/en-us/library/b5e8e7kk(v=vs.71).aspx

<configuration>
 <system.web>
   <webServices>
     <soapExtensionTypes>
      <add type="{Type name}, {Assembly}" priority="1" group="0" />
     </soapExtensionTypes>
    </webServices>
 </system.web>
</configuration>

是的,我不认为这是“普遍接受的方法”。这是一种方式! - phillip
@phillip 好的,改成“常见”的。 - csharptest.net

1
在您的项目中添加一个全局应用程序类Global.asax文件,并将日志记录逻辑添加到Application_BeginRequest()方法中。 sender对象将包含HTTP请求和参数。 您可以仅过滤.asm x请求并记录这些请求。
    protected void Application_BeginRequest(object sender, EventArgs e)
    {

    }

你有日志记录逻辑的示例吗?此外,它将记录每个请求,包括js文件、css文件和图像的请求。我不需要这些。 - Naor
@Naor: ((System.Web.HttpApplication)(sender)).Request 将会给你一个 System.Web.HttpRequest 对象,你可以检查它。你可以检查任何以 .asmx 结尾的 Url 是否为 POST 请求。你只需要记录符合条件的请求。 - tawman
如果AOP和重构不是一个选项,那么通过过滤请求并仅记录您想要记录的Web服务方法可能是最好的选择。 - Martin Buberl

1

编辑--
试试PostSharp吧。这是最简单的获取此功能的方法。为了后人,我将保留下面的帖子,但请忽略它并使用PostSharp。


如果您的 Web 服务是 WCF,则应查看 http://msdn.microsoft.com/en-us/magazine/cc163302.aspx

在每个步骤中,它们都提供了可插入的可扩展性点。 您可以使用这些可扩展性点来实现各种自定义行为,包括消息或参数验证、消息记录、消息转换等。

毫无疑问,这是 WCF 服务的最佳选择。 否则,如果它们只是 Web 服务,则可以使用 Unity 框架并连接截取器来完成相同的操作。


他们有一个社区版,他们的代码片段/示例完全展示了你想要实现的内容,这对现有代码的更改非常少。 - phillip

0
如果编程语言不重要,您可以在服务前面放置Apache Synapse作为代理。然后,您的客户端将向Synapse发送请求,Synapse将委派请求给您的原始服务。代理可以配置为在请求之间执行某些操作,例如记录日志。
请参阅以下链接以获取更多信息:

http://synapse.apache.org/Synapse_Configuration_Language.html#proxy,
http://synapse.apache.org/Synapse_Configuration_Language.html#send,
http://synapse.apache.org/Synapse_Configuration_Language.html#log

以下示例的组合可能适合您:

http://synapse.apache.org/Synapse_Samples.html#Sample0
http://synapse.apache.org/Synapse_Samples.html#ProxyServices

e.g.:

<definitions xmlns="http://ws.apache.org/ns/synapse"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://ws.apache.org/ns/synapse http://synapse.apache.org/ns/2010/04/configuration/synapse_config.xsd">

<proxy name="StockQuoteProxy">
    <target>
        <endpoint>
            <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
        </endpoint>
        <outSequence>
            <!-- log all attributes of messages passing through -->
            <log level="full"/>

            <!-- Send the message to implicit destination -->
            <send/>
        </outSequence>
    </target>
    <publishWSDL uri="file:repository/conf/sample/resources/proxy/sample_proxy_1.wsdl"/>
</proxy>


我正在使用asp.Net。我不认为推动Apache Synapse是一个好主意。我不需要另一个需要我维护的“系统”。我不喜欢不必要的集成 - 我相信在.NET领域中有解决方案。 - Naor

0

我维护一个开源Web服务框架,通过让所有Web服务继承自一个基类并进行自定义日志记录,您可以轻松实现此目标。

这里是一个基类示例,我在其中维护了一个分布式滚动日志,用于记录Redis中的所有异常 - 这是一个非常快速的NoSQL数据存储:

public object Execute(TRequest request)
{
    try
    {
        //Run the request in a managed scope serializing all 
        return Run(request);
    }
    catch (Exception ex)
    {
        return HandleException(request, ex);
    }
}

protected object HandleException(TRequest request, Exception ex)
{
    var responseStatus = ResponseStatusTranslator.Instance.Parse(ex);

    if (EndpointHost.UserConfig.DebugMode)
    {
        // View stack trace in tests and on the client
        responseStatus.StackTrace = GetRequestErrorBody() + ex;
    }

    Log.Error("ServiceBase<TRequest>::Service Exception", ex);

    //If Redis is configured, maintain rolling service error logs in Redis (an in-memory datastore)
    var redisManager = TryResolve<IRedisClientsManager>();
    if (redisManager != null)
    {
        try
        {
            //Get a thread-safe redis client from the client manager pool
            using (var client = redisManager.GetClient())
            {
                //Get a client with a native interface for storing 'ResponseStatus' objects
                var redis = client.GetTypedClient<ResponseStatus>();

                //Store the errors in predictable Redis-named lists i.e. 
                //'urn:ServiceErrors:{ServiceName}' and 'urn:ServiceErrors:All' 
                var redisSeriviceErrorList = redis.Lists[UrnId.Create(UrnServiceErrorType, ServiceName)];
                var redisCombinedErrorList = redis.Lists[UrnId.Create(UrnServiceErrorType, CombinedServiceLogId)];

                //Append the error at the start of the service-specific and combined error logs.
                redisSeriviceErrorList.Prepend(responseStatus);
                redisCombinedErrorList.Prepend(responseStatus);

                //Clip old error logs from the managed logs
                const int rollingErrorCount = 1000;
                redisSeriviceErrorList.Trim(0, rollingErrorCount);
                redisCombinedErrorList.Trim(0, rollingErrorCount);
            }
        }
        catch (Exception suppressRedisException)
        {
            Log.Error("Could not append exception to redis service error logs", suppressRedisException);
        }
    }

    var responseDto = CreateResponseDto(request, responseStatus);

    if (responseDto == null)
    {
        throw ex;
    }

    return new HttpResult(responseDto, null, HttpStatusCode.InternalServerError);
}

否则,对于普通的ASP.NET Web服务框架,我会查看Global.asax事件,特别是“Application_BeginRequest”事件,每次收到新请求时都会触发。

3
@mythz:请披露您与ServiceStack的关系。虽然这是一个开源项目,但像这样做出推荐仍然会被视为垃圾邮件。这不是我第一次看到你推荐ServiceStack了。除此之外,您还没有展示它如何解决这个问题。 - John Saunders
我已经提出了一个建议,如果他使用另一个Web服务框架,就可以轻松实现。原始问题没有指定是哪个框架。我的原始答案还提供了Global.asax事件的位置,让他实现他的目标。为什么你不自己提供一个更好的答案呢?我个人认为,你对特定的Web服务技术/框架的规范是你行为的主要动机。 - mythz
1
@mythz:在我看来,他似乎是在指定ASP.NET Web服务。这一点以及我从未听说过ServiceStack可能与我礼貌地要求您披露有关。谢谢您这样做,并希望您每次推荐此框架时都能这样做。您还应该明智地展示您的框架如何解决此问题。 - John Saunders
ServiceStack是一个ASP.NET Web服务框架。我也提供了一个ASP.NET答案。但需要注意的是,我会尽力让披露更明显。 - mythz
1
@mythz:我正在寻找解决方案来处理asp.NET Web服务。你有什么解决方案吗? - Naor
当然可以 :) 查看http://servicestack.net或https://github.com/mythz/ServiceStack获取信息。 如有任何问题,请随时在http://groups.google.com/group/servicestack上提问。 - mythz

0

你考虑过编写自己的HttpModule吗?这样就不需要修改现有的Web服务代码了。你只需要将你的模块添加到每个web.config文件中即可。


我可以像你的方法一样使用global.asax。你的方法会记录每个请求,包括js文件、css文件和图像的请求。但是我不需要这些。 - Naor

-1

如果这是你要找的内容,就在你的WCF配置文件中加上这段代码:

它会创建非常详细的日志,你可以使用Microsoft Service Trace Viewer来阅读。

<system.diagnostics>
  <sources>
   <source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing">
    <listeners>
     <add type="System.Diagnostics.DefaultTraceListener" name="Default">
      <filter type="" />
     </add>
     <add name="ServiceModelMessageLoggingListener">
      <filter type="" />
     </add>
    </listeners>
   </source>
   <source name="System.ServiceModel" switchValue="Warning, ActivityTracing"
    propagateActivity="true">
    <listeners>
     <add type="System.Diagnostics.DefaultTraceListener" name="Default">
      <filter type="" />
     </add>
     <add name="ServiceModelTraceListener">
      <filter type="" />
     </add>
    </listeners>
   </source>
  </sources>
  <sharedListeners>
   <add initializeData="C:\ServiceLog.svclog"
    type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
    name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
    <filter type="" />
   </add>
   <add initializeData="C:\Tracelog.svclog"
    type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
    name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
    <filter type="" />
   </add>
  </sharedListeners>
 </system.diagnostics>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接