在中间件中记录访问信息


在我网站中,使用的是sqlite保存的日志记录,所以NLog需要sqlite相关的配置

访问记录表的DDL

create table AccessRecord (
  id integer not null constraint AccessRecord_pk primary key autoincrement, 
  AccessUrl nvarchar(1000), 
  ClientIp nvarchar(300), 
  ContentType nvarchar(500), 
  Duration integer, 
  StartTime datetime, 
  Ticks integer, 
  Method nvarchar(50), 
  Referrer nvarchar(1000), 
  UserAgent nvarchar(500), 
  Identity nvarchar(500), 
  Controller nvarchar(100), 
  Action nvarchar(100)
);
create unique index AccessRecord_id_uindex on AccessRecord (id);

然后在nlog.config中配置

<?xml version="1.0" encoding="utf-8"?>

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      throwConfigExceptions="true"
      autoReload="true"
>
	<extensions>
        <add assembly="NLog.Web.AspNetCore" />
    </extensions>
	 <targets async="true">
	 	<!-- name:目标名称,规则中配置写向哪个目标 -->
	 	<target xsi:type="Database"
                name="AccessRecord"
                dbProvider="System.Data.SQLite.SQLiteConnection, System.Data.SQLite"
                connectionString="这里配置sqlite的连接字符串">
            <install-command commandType="text">
				<!--安装表的DDL-->
                <text>
                    create table AccessRecord
                    (
                    id integer not null
                    constraint AccessRecord_pk
                    primary key autoincrement,
                    AccessUrl nvarchar(1000),
                    ClientIp nvarchar(300),
                    ContentType nvarchar(500),
                    Duration integer,
                    StartTime datetime,
                    Ticks integer,
                    Method nvarchar(50),
                    Referrer nvarchar(1000),
                    UserAgent nvarchar(500),
                    Identity nvarchar(500),
                    Controller nvarchar(100),
                    Action nvarchar(100)
                    );

                    create unique index AccessRecord_id_uindex
                    on AccessRecord (id);
                </text>
                <ignoreFailures>false</ignoreFailures>
            </install-command>
			<!--添加日志的sql语句-->
            <commandText>
                INSERT INTO AccessRecord (AccessUrl, ClientIp, ContentType, Duration, StartTime, Ticks, Method, Referrer, UserAgent, Identity, Controller, Action)
                VALUES (@AccessUrl, @ClientIp, @ContentType, @Duration, @StartTime, @Ticks, @Method, @Referrer, @UserAgent, @Identity, @Controller, @Action);
            </commandText>
			<!--sql语句中的相关参数-->
			
			<!--访问地址-->
            <parameter name="@AccessUrl" layout="${aspnet-request-url:IncludeHost=true:IncludePort=true:IncludeQueryString=true:IncludeScheme=true}" />
            <!--客户端IP,因为网站启用了CDN,所以根据Http Headers中的X-Forwarede-For获取IP-->
			<parameter name="@ClientIp" layout="${aspnet-request-headers:HeaderNames=X-Forwarded-For:ValuesOnly=true}" />
            <parameter name="@ContentType" layout="${aspnet-request-contenttype}" />
			<!--消耗时间,将会在中间件中计算,并传递给message,所以这里获取message-->
            <parameter name="@Duration" layout="${message}" />
            <!--开始请求时间-->
			<parameter name="@StartTime" layout="${longdate:universalTime=False}" />
            <!--Ticks-->
			<parameter name="@Ticks" layout="${ticks}" />
            <!--请求方法:GET/POST/PUT/DELETE 等-->
			<parameter name="@Method" layout="${aspnet-request-method}" />
			<!--Http Headers中的Referrer-->
            <parameter name="@Referrer" layout="${aspnet-request-referrer}" />
            <!--Http Heasers中的UserAgent-->
			<parameter name="@UserAgent" layout="${aspnet-request-useragent}" />
            <!--请求用户的身份信息,没有身份验证的为空-->
			<parameter name="@Identity" layout="${aspnet-user-identity}" />
			<!--该请求的Controller-->
            <parameter name="@Controller" layout="${aspnet-mvc-controller}" />
            <!--该请求的Action-->
			<parameter name="@Action" layout="${aspnet-mvc-action}" />
        </target>
	 </targets>
	 <!--配置规则-->
	 <rules>
	 	<!--name:looger名称 ,writeTo要写向哪个目标-->
        <logger name="http access record" minlevel="Debug" writeTo="AccessRecord" />
    </rules>
</nlog>

然后使用中间件来记录日志,具体实现:

public class HttpRequestRecord
{
	private readonly RequestDelegate _next;

	public HttpRequestRecord(RequestDelegate next)
	{
		_next = next;
	}

	public async Task Invoke(HttpContext httpContext, ILoggerFactory loggerFactory)
	{
		// CheckAuthorizeAttribute 是身份认证的特性,所有访问标注了该特性的action都不记录 。
		// runtask 是Hangfire仪表盘的url,也不记录
		var path = httpContext.Request.Path.Value;
		var endpoint = httpContext.Features.Get<IEndpointFeature>()?.Endpoint;
		var attribute = endpoint?.Metadata.GetMetadata<CheckAuthorizeAttribute>();
		if (attribute != null
			|| (path != null && path.StartsWith("/runtask",StringComparison.CurrentCultureIgnoreCase))
		)
		{
		   
	#if DEBUG
			var temp = attribute == null ? "no authorize" : "permissions:" + attribute.Permissions;
			Console.WriteLine(httpContext.Request.GetEncodedUrl() + "\n\t" + temp);
	#endif
			await _next.Invoke(httpContext);
			return;
		}
		// 创建名为 http access record 的Logger
		var logger = loggerFactory.CreateLogger("http access record");
		//记录访问时长
		var watch = Stopwatch.StartNew();
		await _next.Invoke(httpContext);
		watch.Stop();
		//写入日志
		logger.LogInformation(watch.ElapsedMilliseconds.ToString());
	}
}

然后在Startup.cs中调用中间件
app.UseMiddleware<HttpRequestRecord>()


文章作者: 彭迁
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 彭迁 !
  目录