├── src └── Serilog.Sinks.TencentCloud │ ├── FodyWeavers.xml │ ├── TencentCloud │ ├── Time.cs │ ├── cls.proto │ ├── ClsHttpClient.cs │ ├── Authorization.cs │ ├── Signature.cs │ └── Cls.cs │ ├── Sinks │ └── Http │ │ ├── IBatchFormatter.cs │ │ ├── IHttpClient.cs │ │ ├── TencentCloudSink.cs │ │ └── BatchFormatters │ │ └── ClsFormatter.cs │ ├── Serilog.Sinks.TencentCloud.csproj │ ├── FodyWeavers.xsd │ └── LoggerSinkConfigurationExtensions.cs ├── README.md ├── common.props ├── Serilog.Sinks.TencentCloud.sln ├── .github └── workflows │ └── dotnet-core.yml ├── .gitattributes └── .gitignore /src/Serilog.Sinks.TencentCloud/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/TencentCloud/Time.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Serilog.Sinks.TencentCloud 6 | { 7 | public static class Time 8 | { 9 | public static string GetTencentCloudTimeStamp(this DateTimeOffset offset) 10 | { 11 | var endOffset = offset.AddHours(1); 12 | return $"{offset.ToUnixTimeSeconds()};{endOffset.ToUnixTimeSeconds()}"; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/Sinks/Http/IBatchFormatter.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Serilog.Sinks.TencentCloud.Sinks.Http 7 | { 8 | public interface IBatchFormatter 9 | { 10 | /// 11 | /// Format the log events 12 | /// 13 | /// 14 | /// The events to format. 15 | /// 16 | byte[] Format(IEnumerable logEvents); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/TencentCloud/cls.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package TencentCloud.Cls; 3 | message Log 4 | { 5 | message Content 6 | { 7 | string key = 1; // 每组字段的 key 8 | string value = 2; // 每组字段的 value 9 | } 10 | int64 time = 1; // 时间戳,UNIX时间格式 11 | repeated Content contents = 2; // 一条日志里的多个kv组合 12 | } 13 | message LogGroup 14 | { 15 | repeated Log logs = 1; // 多条日志合成的日志数组 16 | string contextFlow = 2; // 目前暂无效用 17 | string filename = 3; // 日志文件名 18 | string source = 4; // 日志来源,一般使用机器IP 19 | } 20 | message LogGroupList 21 | { 22 | repeated LogGroup logGroupList = 1; // 日志组列表 23 | } -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/Serilog.Sinks.TencentCloud.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Serilog.Sinks.TencentCloud 2 | 3 | ## How to use it 4 | 5 | ``` 6 | Log.Logger = new LoggerConfiguration() 7 | .WriteTo.TencentCloud("请求域名(ap-guangzhou.cls.myqcloud.com)", "topic_id(b8c1fafe-677a-4cc2-9c26-d962d5caa077)", "TencentCloud API Sercet Id", "TencentCloud API Sercet Key", restrictedToMinimumLevel: LogEventLevel.Warning) 8 | .CreateLogger() 9 | ``` 10 | 11 | Used in conjunction with Serilog.Settings.Configuration the same sink can be configured in the following way: 12 | 13 | ``` 14 | { 15 | "Serilog": { 16 | "MinimumLevel": "Verbose", 17 | "WriteTo": [ 18 | { 19 | "Name": "TencentCloud", 20 | "Args": { 21 | "requestBaseUri": "ap-guangzhou.cls.myqcloud.com", 22 | "topicId": "", 23 | "secretId": "", 24 | "secretKey": "" 25 | } 26 | } 27 | ] 28 | } 29 | } 30 | ``` -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/Sinks/Http/IHttpClient.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Sinks.TencentCloud; 2 | using System; 3 | using System.Net.Http; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Serilog.Sinks.Http 8 | { 9 | /// 10 | /// Interface responsible for posting HTTP requests. 11 | /// 12 | public interface IHttpClient 13 | { 14 | /// 15 | /// Sends a POST request to the specified Uri as an asynchronous operation. 16 | /// 17 | /// The Uri the request is sent to. 18 | /// The HTTP request content sent to the server. 19 | /// The task object representing the asynchronous operation. 20 | Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default); 21 | } 22 | } -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/TencentCloud/ClsHttpClient.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Serilog.Sinks.Http; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Net.Http; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace Serilog.Sinks.TencentCloud 11 | { 12 | public class ClsHttpClient : IHttpClient 13 | { 14 | private readonly Authorization authorization; 15 | private readonly HttpClient client; 16 | 17 | public ClsHttpClient(Authorization authorization) 18 | { 19 | this.authorization = authorization; 20 | client = new HttpClient(); 21 | } 22 | 23 | public async Task PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken = default) 24 | { 25 | client.DefaultRequestHeaders.Clear(); 26 | client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", authorization.GetAuthorizationString()); 27 | return await client.PostAsync(requestUri, content, cancellationToken); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /common.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | latest 4 | 1.0.4 5 | $(NoWarn);CS1591 6 | true 7 | EasyAbp Team 8 | Serilog扩展将日志推送到腾讯云cls 9 | https://github.com/EasyAbp/Serilog.Sinks.TencentCloud 10 | https://github.com/EasyAbp/Serilog.Sinks.TencentCloud 11 | 12 | Yhd 13 | MIT 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | all 24 | runtime; build; native; contentfiles; analyzers 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Serilog.Sinks.TencentCloud.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28803.156 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Sinks.TencentCloud", "src\Serilog.Sinks.TencentCloud\Serilog.Sinks.TencentCloud.csproj", "{283AB0D2-6BAF-4701-AE85-C50D0913E10A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {283AB0D2-6BAF-4701-AE85-C50D0913E10A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {283AB0D2-6BAF-4701-AE85-C50D0913E10A}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {283AB0D2-6BAF-4701-AE85-C50D0913E10A}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {283AB0D2-6BAF-4701-AE85-C50D0913E10A}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {A42087CD-8AA8-45E4-9804-7EA9AB80B188} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/TencentCloud/Authorization.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Serilog.Sinks.TencentCloud 6 | { 7 | public class Authorization 8 | { 9 | private long lastEndTime = 0; 10 | 11 | private string authorizationString = ""; 12 | public string SecretKey { get; set; } 13 | 14 | public string SecretId { get; set; } 15 | 16 | /// 17 | /// 获取请求Authorization头部的授权字符串 18 | /// 19 | /// 20 | public string GetAuthorizationString() 21 | { 22 | var timeStr = DateTimeOffset.Now.GetTencentCloudTimeStamp(); 23 | var time = timeStr.Split(';'); 24 | var nowStartTime = Convert.ToInt64(time[0]); 25 | if(lastEndTime > nowStartTime) 26 | { 27 | return authorizationString; 28 | } 29 | lastEndTime = Convert.ToInt64(time[1]); 30 | var signature = Signature.GetSignature("post", "/structuredlog", timeStr, timeStr, SecretKey); 31 | authorizationString = $"q-sign-algorithm=sha1&q-ak={SecretId}&q-sign-time={timeStr}&q-key-time={timeStr}&q-header-list=&q-url-param-list=&q-signature={signature}"; 32 | return authorizationString; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/FodyWeavers.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. 16 | 17 | 18 | 19 | 20 | A comma-separated list of error codes that can be safely ignored in assembly verification. 21 | 22 | 23 | 24 | 25 | 'false' to turn off automatic generation of the XML Schema file. 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /.github/workflows/dotnet-core.yml: -------------------------------------------------------------------------------- 1 | name: publish to nuget 2 | on: 3 | push: 4 | branches: 5 | - master 6 | - main 7 | jobs: 8 | publish: 9 | runs-on: windows-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: NuGet/setup-nuget@v1.0.5 13 | 14 | - name: read common.props 15 | id: commonProps 16 | uses: juliangruber/read-file-action@v1 17 | with: 18 | path: ./common.props 19 | 20 | - name: get version 21 | id: getVersion 22 | uses: AsasInnab/regex-action@v1 23 | with: 24 | regex_pattern: '(?<=>)[^<>]+(?=)' 25 | regex_flags: 'gim' 26 | search_string: '${{ steps.commonProps.outputs.content }}' 27 | 28 | - name: dotnet restore 29 | run: dotnet restore -s "https://api.nuget.org/v3/index.json" 30 | 31 | - name: dotnet build 32 | run: dotnet build -c Release 33 | 34 | - name: dotnet pack 35 | run: dotnet pack -c Release --no-build -o dest 36 | 37 | - name: remove unused packages 38 | run: | 39 | cd dest 40 | del * -Exclude Serilog.Sinks.* 41 | del * -Exclude *.${{ steps.getVersion.outputs.first_match }}.nupkg 42 | del *.HttpApi.Client.ConsoleTestApp* 43 | del *.Host.Shared* 44 | dir -name 45 | 46 | - name: dotnet nuget push to GitHub 47 | uses: tanaka-takayoshi/nuget-publish-to-github-packages-action@v2.1 48 | with: 49 | nupkg-path: 'dest\*.nupkg' 50 | repo-owner: 'EasyAbp' 51 | gh-user: 'EasyAbp' 52 | token: ${{ secrets.GITHUB_TOKEN }} 53 | 54 | - name: dotnet nuget push to NuGet 55 | run: dotnet nuget push dest\*.nupkg -k ${{secrets.NUGET_API_KEY}} -s https://api.nuget.org/v3/index.json --skip-duplicate 56 | 57 | - name: determine if the tag exists 58 | uses: mukunku/tag-exists-action@v1.0.0 59 | id: checkTag 60 | with: 61 | tag: ${{ steps.getVersion.outputs.first_match }} 62 | env: 63 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 64 | 65 | - name: add git tag 66 | if: ${{ steps.checkTag.outputs.exists == 'false' }} 67 | uses: tvdias/github-tagger@v0.0.1 68 | with: 69 | repo-token: ${{ secrets.GITHUB_TOKEN }} 70 | tag: ${{ steps.getVersion.outputs.first_match }} 71 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/LoggerSinkConfigurationExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Serilog.Configuration; 3 | using Serilog.Events; 4 | using Serilog.Sinks.Http; 5 | using Serilog.Sinks.TencentCloud; 6 | using Serilog.Sinks.TencentCloud.Sinks.Http; 7 | using Serilog.Sinks.TencentCloud.Sinks.Http.BatchFormatters; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Net.Http; 11 | using System.Text; 12 | 13 | namespace Serilog 14 | {/// 15 | /// Adds the WriteTo.TencentCloud() extension method to 16 | /// . 17 | /// 18 | public static class LoggerSinkConfigurationExtensions 19 | { 20 | /// 21 | /// 22 | /// 23 | /// Like ap-guangzhou.cls.myqcloud.com/ 24 | /// 日志主题 ID 25 | /// 腾讯云API调用授权所需secretId 26 | /// 腾讯云API调用授权所需secretKey 27 | /// 28 | public static LoggerConfiguration TencentCloud( 29 | this LoggerSinkConfiguration sinkConfiguration, 30 | string requestBaseUri, 31 | string topicId, 32 | string secretId, 33 | string secretKey, 34 | int batchPostingLimit = 1000, 35 | int? queueLimit = null, 36 | TimeSpan? period = null, 37 | ClsFormatter clsFormatter = null, 38 | LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, 39 | IHttpClient httpClient = null) 40 | { 41 | var authorization = new Authorization() 42 | { 43 | SecretId = secretId, 44 | SecretKey = secretKey, 45 | }; 46 | 47 | if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration)); 48 | 49 | // Default values 50 | period = period ?? TimeSpan.FromSeconds(2); 51 | clsFormatter = clsFormatter ?? new ClsFormatter(); 52 | 53 | httpClient = httpClient ?? new ClsHttpClient(authorization); 54 | 55 | var sink = queueLimit != null 56 | ? new TencentCloudSink($"http://{requestBaseUri}/structuredlog?topic_id={topicId}", batchPostingLimit, period.Value, queueLimit.Value, httpClient, clsFormatter) 57 | : new TencentCloudSink($"http://{requestBaseUri}/structuredlog?topic_id={topicId}", batchPostingLimit, period.Value, httpClient, clsFormatter ); 58 | 59 | return sinkConfiguration.Sink(sink, restrictedToMinimumLevel); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/TencentCloud/Signature.cs: -------------------------------------------------------------------------------- 1 | using NETCore.Encrypt.Extensions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Serilog.Sinks.TencentCloud 7 | { 8 | public static class Signature 9 | { 10 | /// 11 | /// 12 | /// 13 | /// HTTP 请求使用的方法,小写字母,如 get、post等 14 | /// HTTP 请求的资源名称,不包含 query string 部分,如 /logset 15 | /// HttpRequestInfo 16 | private static string GetHttpRequestInfo(string method, string uri) 17 | { 18 | return $"{method}\n{uri}\n\n\n"; 19 | } 20 | 21 | /// 22 | /// 23 | /// 24 | /// 签名算法,目前仅支持 sha1 25 | /// 签名有效起止时间,Unix时间戳,以秒为单位,;分隔 26 | /// HttpRequestInfo 27 | /// 28 | private static string GetStringToSign(string q_sign_algorithm, string q_sign_time, string httpRequestInfo) 29 | { 30 | return $"{q_sign_algorithm}\n{q_sign_time}\n{httpRequestInfo.SHA1()}\n".ToLower(); 31 | } 32 | 33 | /// 34 | /// 35 | /// 36 | /// Unix时间戳,以秒为单位,;分隔 37 | /// 腾讯云API的SecretKey 38 | /// 39 | private static string GetSignKey(string q_key_time, string secretKey) 40 | { 41 | return q_key_time.HMACSHA1(secretKey).ToLower(); 42 | } 43 | /// 44 | /// 获取签名 45 | /// 46 | /// StringToSign 47 | /// SignKey 48 | /// 49 | private static string GetSignature(string stringToSign, string signKey) 50 | { 51 | return stringToSign.HMACSHA1(signKey).ToLower(); 52 | } 53 | 54 | /// 55 | /// 获取签名字符串 56 | /// 57 | /// HTTP 请求使用的方法,小写字母,如 get、post等 58 | /// HTTP 请求的资源名称,不包含 query string 部分,如 /logset 59 | /// 签名算法,目前仅支持 sha1 60 | /// 签名有效起止时间,Unix时间戳,以秒为单位,;分隔 61 | /// Unix时间戳,以秒为单位,;分隔 62 | /// 腾讯云API的SecretKey 63 | /// Signature签名字符串 64 | public static string GetSignature(string method, string uri, string q_sign_time, string q_key_time, string secretKey) 65 | { 66 | var httpRequestInfo = GetHttpRequestInfo(method, uri); 67 | var stringToSign = GetStringToSign("sha1", q_sign_time, httpRequestInfo); 68 | var signKey = GetSignKey(q_key_time, secretKey); 69 | 70 | return GetSignature(stringToSign, signKey); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/Sinks/Http/TencentCloudSink.cs: -------------------------------------------------------------------------------- 1 | using Serilog.Debugging; 2 | using Serilog.Events; 3 | using Serilog.Sinks.Http; 4 | using Serilog.Sinks.PeriodicBatching; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Net.Http; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Serilog.Sinks.TencentCloud.Sinks.Http 12 | { 13 | public class TencentCloudSink : PeriodicBatchingSink 14 | { 15 | private const string ContentType = "application/x-protobuf"; 16 | 17 | private readonly string requestUri; 18 | private readonly IBatchFormatter clsFormatter; 19 | 20 | private IHttpClient client; 21 | public TencentCloudSink(string requestUri, int batchSizeLimit, TimeSpan period, IHttpClient client, IBatchFormatter clsFormatter) 22 | : base(batchSizeLimit, period) 23 | { 24 | this.requestUri = requestUri ?? throw new ArgumentNullException(nameof(requestUri)); 25 | this.clsFormatter = clsFormatter ?? throw new ArgumentNullException(nameof(clsFormatter)); 26 | this.client = client ?? throw new ArgumentNullException(nameof(client)); 27 | } 28 | 29 | public TencentCloudSink(string requestUri, int batchSizeLimit, TimeSpan period, int queueLimit, IHttpClient client, IBatchFormatter clsFormatter) 30 | : base(batchSizeLimit, period, queueLimit) 31 | { 32 | this.requestUri = requestUri ?? throw new ArgumentNullException(nameof(requestUri)); 33 | this.clsFormatter = clsFormatter ?? throw new ArgumentNullException(nameof(clsFormatter)); 34 | this.client = client ?? throw new ArgumentNullException(nameof(client)); 35 | } 36 | 37 | 38 | /// 39 | /// Emit a batch of log events, running asynchronously. 40 | /// 41 | protected override async Task EmitBatchAsync(IEnumerable logEvents) 42 | { 43 | var logs = clsFormatter.Format(logEvents); 44 | 45 | var content = new ByteArrayContent(logs); //new StringContent(logs); 46 | content.Headers.Clear(); 47 | content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(ContentType); 48 | var result = await client 49 | .PostAsync(requestUri, content); 50 | 51 | if (!result.IsSuccessStatusCode) 52 | { 53 | throw new LoggingFailedException($"Received failed result {result.StatusCode} when posting events to {requestUri}"); 54 | } 55 | } 56 | 57 | /// 58 | /// Free resources held by the sink. 59 | /// 60 | /// 61 | /// If true, called because the object is being disposed; if false, the object is being 62 | /// disposed from the finalizer. 63 | /// 64 | protected override void Dispose(bool disposing) 65 | { 66 | base.Dispose(disposing); 67 | 68 | if (disposing) 69 | { 70 | client = null; 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/Sinks/Http/BatchFormatters/ClsFormatter.cs: -------------------------------------------------------------------------------- 1 | using Google.Protobuf; 2 | using ProtoBuf; 3 | using Serilog.Debugging; 4 | using Serilog.Events; 5 | using Serilog.Formatting.Json; 6 | using Serilog.Parsing; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Text; 12 | 13 | namespace Serilog.Sinks.TencentCloud.Sinks.Http.BatchFormatters 14 | { 15 | public class ClsFormatter : IBatchFormatter 16 | { 17 | public byte[] Format(IEnumerable logEvents) 18 | { 19 | if (logEvents == null) throw new ArgumentNullException(nameof(logEvents)); 20 | 21 | var logGroup = new global::TencentCloud.Cls.LogGroup(); 22 | 23 | foreach (var logEvent in logEvents) 24 | { 25 | var log = new global::TencentCloud.Cls.Log(); 26 | try 27 | { 28 | var contents = GetLogEventContents(logEvent); 29 | log.Contents.AddRange(contents); 30 | log.Time = logEvent.Timestamp.ToUnixTimeMilliseconds(); 31 | } 32 | catch (Exception e) 33 | { 34 | LogNonFormattableEvent(logEvent, e); 35 | } 36 | logGroup.Logs.Add(log); 37 | } 38 | var logGroupList = new global::TencentCloud.Cls.LogGroupList(); 39 | logGroupList.LogGroupList_.Add(logGroup); 40 | 41 | return logGroupList.ToByteArray(); 42 | } 43 | 44 | private List GetLogEventContents(LogEvent logEvent) 45 | { 46 | var contents = new List(); 47 | var sw1 = new StringWriter(); 48 | contents.Add(new global::TencentCloud.Cls.Log.Types.Content 49 | { 50 | Key = "Timestamp", 51 | Value = logEvent.Timestamp.ToString("o") 52 | }); 53 | contents.Add(new global::TencentCloud.Cls.Log.Types.Content 54 | { 55 | Key = "Level", 56 | Value = logEvent.Level.ToString() 57 | }); 58 | JsonValueFormatter.WriteQuotedJsonString(logEvent.MessageTemplate.Text, sw1); 59 | contents.Add(new global::TencentCloud.Cls.Log.Types.Content 60 | { 61 | Key = "MessageTemplate", 62 | Value = sw1.ToString() 63 | }); 64 | sw1.Flush(); 65 | var message = logEvent.MessageTemplate.Render(logEvent.Properties); 66 | JsonValueFormatter.WriteQuotedJsonString(message, sw1); 67 | contents.Add(new global::TencentCloud.Cls.Log.Types.Content 68 | { 69 | Key = "RenderedMessage", 70 | Value = sw1.ToString() 71 | }); 72 | sw1.Flush(); 73 | if (logEvent.Exception != null) 74 | { 75 | JsonValueFormatter.WriteQuotedJsonString(logEvent.Exception.ToString(), sw1); 76 | contents.Add(new global::TencentCloud.Cls.Log.Types.Content 77 | { 78 | Key = "Exception", 79 | Value = sw1.ToString() 80 | }); 81 | } 82 | 83 | if (logEvent.Properties.Count != 0) 84 | { 85 | var sw = new StringWriter(); 86 | WriteProperties(logEvent.Properties, sw); 87 | contents.Add(new global::TencentCloud.Cls.Log.Types.Content 88 | { 89 | Key = "Properties", 90 | Value = sw.ToString() 91 | }); 92 | } 93 | // Better not to allocate an array in the 99.9% of cases where this is false 94 | var tokensWithFormat = logEvent.MessageTemplate.Tokens 95 | .OfType() 96 | .Where(pt => pt.Format != null); 97 | // ReSharper disable once PossibleMultipleEnumeration 98 | if (tokensWithFormat.Any()) 99 | { 100 | var output = new StringWriter(); 101 | // ReSharper disable once PossibleMultipleEnumeration 102 | WriteRenderings(tokensWithFormat.GroupBy(pt => pt.PropertyName), logEvent.Properties, output); 103 | contents.Add(new global::TencentCloud.Cls.Log.Types.Content 104 | { 105 | Key = "Renderings", 106 | Value = output.ToString() 107 | }); 108 | } 109 | return contents; 110 | 111 | } 112 | private static void WriteProperties( 113 | IReadOnlyDictionary properties, 114 | TextWriter output) 115 | { 116 | output.Write("{"); 117 | 118 | var precedingDelimiter = ""; 119 | 120 | foreach (var property in properties) 121 | { 122 | output.Write(precedingDelimiter); 123 | precedingDelimiter = ","; 124 | 125 | JsonValueFormatter.WriteQuotedJsonString(property.Key, output); 126 | output.Write(':'); 127 | new JsonValueFormatter().Format(property.Value, output); 128 | } 129 | 130 | output.Write('}'); 131 | } 132 | 133 | private static void WriteRenderings( 134 | IEnumerable> tokensWithFormat, 135 | IReadOnlyDictionary properties, 136 | TextWriter output) 137 | { 138 | output.Write("{"); 139 | 140 | var rdelim = ""; 141 | foreach (var ptoken in tokensWithFormat) 142 | { 143 | output.Write(rdelim); 144 | rdelim = ","; 145 | 146 | JsonValueFormatter.WriteQuotedJsonString(ptoken.Key, output); 147 | output.Write(":["); 148 | 149 | var fdelim = ""; 150 | foreach (var format in ptoken) 151 | { 152 | output.Write(fdelim); 153 | fdelim = ","; 154 | 155 | output.Write("{\"Format\":"); 156 | JsonValueFormatter.WriteQuotedJsonString(format.Format, output); 157 | 158 | output.Write(",\"Rendering\":"); 159 | var sw = new StringWriter(); 160 | format.Render(properties, sw); 161 | JsonValueFormatter.WriteQuotedJsonString(sw.ToString(), output); 162 | output.Write('}'); 163 | } 164 | 165 | output.Write(']'); 166 | } 167 | 168 | output.Write('}'); 169 | } 170 | 171 | 172 | private static void LogNonFormattableEvent(LogEvent logEvent, Exception e) 173 | { 174 | SelfLog.WriteLine( 175 | "Event at {0} with message template {1} could not be formatted into JSON and will be dropped: {2}", 176 | logEvent.Timestamp.ToString("o"), 177 | logEvent.MessageTemplate.Text, 178 | e); 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/Serilog.Sinks.TencentCloud/TencentCloud/Cls.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by the protocol buffer compiler. DO NOT EDIT! 3 | // source: cls.proto 4 | // 5 | #pragma warning disable 1591, 0612, 3021 6 | #region Designer generated code 7 | 8 | using pb = global::Google.Protobuf; 9 | using pbc = global::Google.Protobuf.Collections; 10 | using pbr = global::Google.Protobuf.Reflection; 11 | using scg = global::System.Collections.Generic; 12 | namespace TencentCloud.Cls { 13 | 14 | /// Holder for reflection information generated from cls.proto 15 | public static partial class ClsReflection { 16 | 17 | #region Descriptor 18 | /// File descriptor for cls.proto 19 | public static pbr::FileDescriptor Descriptor { 20 | get { return descriptor; } 21 | } 22 | private static pbr::FileDescriptor descriptor; 23 | 24 | static ClsReflection() { 25 | byte[] descriptorData = global::System.Convert.FromBase64String( 26 | string.Concat( 27 | "CgljbHMucHJvdG8SEFRlbmNlbnRDbG91ZC5DbHMiawoDTG9nEgwKBHRpbWUY", 28 | "ASABKAMSLwoIY29udGVudHMYAiADKAsyHS5UZW5jZW50Q2xvdWQuQ2xzLkxv", 29 | "Zy5Db250ZW50GiUKB0NvbnRlbnQSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIg", 30 | "ASgJImYKCExvZ0dyb3VwEiMKBGxvZ3MYASADKAsyFS5UZW5jZW50Q2xvdWQu", 31 | "Q2xzLkxvZxITCgtjb250ZXh0RmxvdxgCIAEoCRIQCghmaWxlbmFtZRgDIAEo", 32 | "CRIOCgZzb3VyY2UYBCABKAkiQAoMTG9nR3JvdXBMaXN0EjAKDGxvZ0dyb3Vw", 33 | "TGlzdBgBIAMoCzIaLlRlbmNlbnRDbG91ZC5DbHMuTG9nR3JvdXBiBnByb3Rv", 34 | "Mw==")); 35 | descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, 36 | new pbr::FileDescriptor[] { }, 37 | new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { 38 | new pbr::GeneratedClrTypeInfo(typeof(global::TencentCloud.Cls.Log), global::TencentCloud.Cls.Log.Parser, new[]{ "Time", "Contents" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::TencentCloud.Cls.Log.Types.Content), global::TencentCloud.Cls.Log.Types.Content.Parser, new[]{ "Key", "Value" }, null, null, null)}), 39 | new pbr::GeneratedClrTypeInfo(typeof(global::TencentCloud.Cls.LogGroup), global::TencentCloud.Cls.LogGroup.Parser, new[]{ "Logs", "ContextFlow", "Filename", "Source" }, null, null, null), 40 | new pbr::GeneratedClrTypeInfo(typeof(global::TencentCloud.Cls.LogGroupList), global::TencentCloud.Cls.LogGroupList.Parser, new[]{ "LogGroupList_" }, null, null, null) 41 | })); 42 | } 43 | #endregion 44 | 45 | } 46 | #region Messages 47 | public sealed partial class Log : pb::IMessage { 48 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Log()); 49 | private pb::UnknownFieldSet _unknownFields; 50 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 51 | public static pb::MessageParser Parser { get { return _parser; } } 52 | 53 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 54 | public static pbr::MessageDescriptor Descriptor { 55 | get { return global::TencentCloud.Cls.ClsReflection.Descriptor.MessageTypes[0]; } 56 | } 57 | 58 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 59 | pbr::MessageDescriptor pb::IMessage.Descriptor { 60 | get { return Descriptor; } 61 | } 62 | 63 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 64 | public Log() { 65 | OnConstruction(); 66 | } 67 | 68 | partial void OnConstruction(); 69 | 70 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 71 | public Log(Log other) : this() { 72 | time_ = other.time_; 73 | contents_ = other.contents_.Clone(); 74 | _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); 75 | } 76 | 77 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 78 | public Log Clone() { 79 | return new Log(this); 80 | } 81 | 82 | /// Field number for the "time" field. 83 | public const int TimeFieldNumber = 1; 84 | private long time_; 85 | /// 86 | /// 时间戳,UNIX时间格式 87 | /// 88 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 89 | public long Time { 90 | get { return time_; } 91 | set { 92 | time_ = value; 93 | } 94 | } 95 | 96 | /// Field number for the "contents" field. 97 | public const int ContentsFieldNumber = 2; 98 | private static readonly pb::FieldCodec _repeated_contents_codec 99 | = pb::FieldCodec.ForMessage(18, global::TencentCloud.Cls.Log.Types.Content.Parser); 100 | private readonly pbc::RepeatedField contents_ = new pbc::RepeatedField(); 101 | /// 102 | /// 一条日志里的多个kv组合 103 | /// 104 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 105 | public pbc::RepeatedField Contents { 106 | get { return contents_; } 107 | } 108 | 109 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 110 | public override bool Equals(object other) { 111 | return Equals(other as Log); 112 | } 113 | 114 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 115 | public bool Equals(Log other) { 116 | if (ReferenceEquals(other, null)) { 117 | return false; 118 | } 119 | if (ReferenceEquals(other, this)) { 120 | return true; 121 | } 122 | if (Time != other.Time) return false; 123 | if(!contents_.Equals(other.contents_)) return false; 124 | return Equals(_unknownFields, other._unknownFields); 125 | } 126 | 127 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 128 | public override int GetHashCode() { 129 | int hash = 1; 130 | if (Time != 0L) hash ^= Time.GetHashCode(); 131 | hash ^= contents_.GetHashCode(); 132 | if (_unknownFields != null) { 133 | hash ^= _unknownFields.GetHashCode(); 134 | } 135 | return hash; 136 | } 137 | 138 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 139 | public override string ToString() { 140 | return pb::JsonFormatter.ToDiagnosticString(this); 141 | } 142 | 143 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 144 | public void WriteTo(pb::CodedOutputStream output) { 145 | if (Time != 0L) { 146 | output.WriteRawTag(8); 147 | output.WriteInt64(Time); 148 | } 149 | contents_.WriteTo(output, _repeated_contents_codec); 150 | if (_unknownFields != null) { 151 | _unknownFields.WriteTo(output); 152 | } 153 | } 154 | 155 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 156 | public int CalculateSize() { 157 | int size = 0; 158 | if (Time != 0L) { 159 | size += 1 + pb::CodedOutputStream.ComputeInt64Size(Time); 160 | } 161 | size += contents_.CalculateSize(_repeated_contents_codec); 162 | if (_unknownFields != null) { 163 | size += _unknownFields.CalculateSize(); 164 | } 165 | return size; 166 | } 167 | 168 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 169 | public void MergeFrom(Log other) { 170 | if (other == null) { 171 | return; 172 | } 173 | if (other.Time != 0L) { 174 | Time = other.Time; 175 | } 176 | contents_.Add(other.contents_); 177 | _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); 178 | } 179 | 180 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 181 | public void MergeFrom(pb::CodedInputStream input) { 182 | uint tag; 183 | while ((tag = input.ReadTag()) != 0) { 184 | switch(tag) { 185 | default: 186 | _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); 187 | break; 188 | case 8: { 189 | Time = input.ReadInt64(); 190 | break; 191 | } 192 | case 18: { 193 | contents_.AddEntriesFrom(input, _repeated_contents_codec); 194 | break; 195 | } 196 | } 197 | } 198 | } 199 | 200 | #region Nested types 201 | /// Container for nested types declared in the Log message type. 202 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 203 | public static partial class Types { 204 | public sealed partial class Content : pb::IMessage { 205 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Content()); 206 | private pb::UnknownFieldSet _unknownFields; 207 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 208 | public static pb::MessageParser Parser { get { return _parser; } } 209 | 210 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 211 | public static pbr::MessageDescriptor Descriptor { 212 | get { return global::TencentCloud.Cls.Log.Descriptor.NestedTypes[0]; } 213 | } 214 | 215 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 216 | pbr::MessageDescriptor pb::IMessage.Descriptor { 217 | get { return Descriptor; } 218 | } 219 | 220 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 221 | public Content() { 222 | OnConstruction(); 223 | } 224 | 225 | partial void OnConstruction(); 226 | 227 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 228 | public Content(Content other) : this() { 229 | key_ = other.key_; 230 | value_ = other.value_; 231 | _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); 232 | } 233 | 234 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 235 | public Content Clone() { 236 | return new Content(this); 237 | } 238 | 239 | /// Field number for the "key" field. 240 | public const int KeyFieldNumber = 1; 241 | private string key_ = ""; 242 | /// 243 | /// 每组字段的 key 244 | /// 245 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 246 | public string Key { 247 | get { return key_; } 248 | set { 249 | key_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); 250 | } 251 | } 252 | 253 | /// Field number for the "value" field. 254 | public const int ValueFieldNumber = 2; 255 | private string value_ = ""; 256 | /// 257 | /// 每组字段的 value 258 | /// 259 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 260 | public string Value { 261 | get { return value_; } 262 | set { 263 | value_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); 264 | } 265 | } 266 | 267 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 268 | public override bool Equals(object other) { 269 | return Equals(other as Content); 270 | } 271 | 272 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 273 | public bool Equals(Content other) { 274 | if (ReferenceEquals(other, null)) { 275 | return false; 276 | } 277 | if (ReferenceEquals(other, this)) { 278 | return true; 279 | } 280 | if (Key != other.Key) return false; 281 | if (Value != other.Value) return false; 282 | return Equals(_unknownFields, other._unknownFields); 283 | } 284 | 285 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 286 | public override int GetHashCode() { 287 | int hash = 1; 288 | if (Key.Length != 0) hash ^= Key.GetHashCode(); 289 | if (Value.Length != 0) hash ^= Value.GetHashCode(); 290 | if (_unknownFields != null) { 291 | hash ^= _unknownFields.GetHashCode(); 292 | } 293 | return hash; 294 | } 295 | 296 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 297 | public override string ToString() { 298 | return pb::JsonFormatter.ToDiagnosticString(this); 299 | } 300 | 301 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 302 | public void WriteTo(pb::CodedOutputStream output) { 303 | if (Key.Length != 0) { 304 | output.WriteRawTag(10); 305 | output.WriteString(Key); 306 | } 307 | if (Value.Length != 0) { 308 | output.WriteRawTag(18); 309 | output.WriteString(Value); 310 | } 311 | if (_unknownFields != null) { 312 | _unknownFields.WriteTo(output); 313 | } 314 | } 315 | 316 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 317 | public int CalculateSize() { 318 | int size = 0; 319 | if (Key.Length != 0) { 320 | size += 1 + pb::CodedOutputStream.ComputeStringSize(Key); 321 | } 322 | if (Value.Length != 0) { 323 | size += 1 + pb::CodedOutputStream.ComputeStringSize(Value); 324 | } 325 | if (_unknownFields != null) { 326 | size += _unknownFields.CalculateSize(); 327 | } 328 | return size; 329 | } 330 | 331 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 332 | public void MergeFrom(Content other) { 333 | if (other == null) { 334 | return; 335 | } 336 | if (other.Key.Length != 0) { 337 | Key = other.Key; 338 | } 339 | if (other.Value.Length != 0) { 340 | Value = other.Value; 341 | } 342 | _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); 343 | } 344 | 345 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 346 | public void MergeFrom(pb::CodedInputStream input) { 347 | uint tag; 348 | while ((tag = input.ReadTag()) != 0) { 349 | switch(tag) { 350 | default: 351 | _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); 352 | break; 353 | case 10: { 354 | Key = input.ReadString(); 355 | break; 356 | } 357 | case 18: { 358 | Value = input.ReadString(); 359 | break; 360 | } 361 | } 362 | } 363 | } 364 | 365 | } 366 | 367 | } 368 | #endregion 369 | 370 | } 371 | 372 | public sealed partial class LogGroup : pb::IMessage { 373 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new LogGroup()); 374 | private pb::UnknownFieldSet _unknownFields; 375 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 376 | public static pb::MessageParser Parser { get { return _parser; } } 377 | 378 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 379 | public static pbr::MessageDescriptor Descriptor { 380 | get { return global::TencentCloud.Cls.ClsReflection.Descriptor.MessageTypes[1]; } 381 | } 382 | 383 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 384 | pbr::MessageDescriptor pb::IMessage.Descriptor { 385 | get { return Descriptor; } 386 | } 387 | 388 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 389 | public LogGroup() { 390 | OnConstruction(); 391 | } 392 | 393 | partial void OnConstruction(); 394 | 395 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 396 | public LogGroup(LogGroup other) : this() { 397 | logs_ = other.logs_.Clone(); 398 | contextFlow_ = other.contextFlow_; 399 | filename_ = other.filename_; 400 | source_ = other.source_; 401 | _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); 402 | } 403 | 404 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 405 | public LogGroup Clone() { 406 | return new LogGroup(this); 407 | } 408 | 409 | /// Field number for the "logs" field. 410 | public const int LogsFieldNumber = 1; 411 | private static readonly pb::FieldCodec _repeated_logs_codec 412 | = pb::FieldCodec.ForMessage(10, global::TencentCloud.Cls.Log.Parser); 413 | private readonly pbc::RepeatedField logs_ = new pbc::RepeatedField(); 414 | /// 415 | /// 多条日志合成的日志数组 416 | /// 417 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 418 | public pbc::RepeatedField Logs { 419 | get { return logs_; } 420 | } 421 | 422 | /// Field number for the "contextFlow" field. 423 | public const int ContextFlowFieldNumber = 2; 424 | private string contextFlow_ = ""; 425 | /// 426 | /// 目前暂无效用 427 | /// 428 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 429 | public string ContextFlow { 430 | get { return contextFlow_; } 431 | set { 432 | contextFlow_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); 433 | } 434 | } 435 | 436 | /// Field number for the "filename" field. 437 | public const int FilenameFieldNumber = 3; 438 | private string filename_ = ""; 439 | /// 440 | /// 日志文件名 441 | /// 442 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 443 | public string Filename { 444 | get { return filename_; } 445 | set { 446 | filename_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); 447 | } 448 | } 449 | 450 | /// Field number for the "source" field. 451 | public const int SourceFieldNumber = 4; 452 | private string source_ = ""; 453 | /// 454 | /// 日志来源,一般使用机器IP 455 | /// 456 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 457 | public string Source { 458 | get { return source_; } 459 | set { 460 | source_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); 461 | } 462 | } 463 | 464 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 465 | public override bool Equals(object other) { 466 | return Equals(other as LogGroup); 467 | } 468 | 469 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 470 | public bool Equals(LogGroup other) { 471 | if (ReferenceEquals(other, null)) { 472 | return false; 473 | } 474 | if (ReferenceEquals(other, this)) { 475 | return true; 476 | } 477 | if(!logs_.Equals(other.logs_)) return false; 478 | if (ContextFlow != other.ContextFlow) return false; 479 | if (Filename != other.Filename) return false; 480 | if (Source != other.Source) return false; 481 | return Equals(_unknownFields, other._unknownFields); 482 | } 483 | 484 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 485 | public override int GetHashCode() { 486 | int hash = 1; 487 | hash ^= logs_.GetHashCode(); 488 | if (ContextFlow.Length != 0) hash ^= ContextFlow.GetHashCode(); 489 | if (Filename.Length != 0) hash ^= Filename.GetHashCode(); 490 | if (Source.Length != 0) hash ^= Source.GetHashCode(); 491 | if (_unknownFields != null) { 492 | hash ^= _unknownFields.GetHashCode(); 493 | } 494 | return hash; 495 | } 496 | 497 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 498 | public override string ToString() { 499 | return pb::JsonFormatter.ToDiagnosticString(this); 500 | } 501 | 502 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 503 | public void WriteTo(pb::CodedOutputStream output) { 504 | logs_.WriteTo(output, _repeated_logs_codec); 505 | if (ContextFlow.Length != 0) { 506 | output.WriteRawTag(18); 507 | output.WriteString(ContextFlow); 508 | } 509 | if (Filename.Length != 0) { 510 | output.WriteRawTag(26); 511 | output.WriteString(Filename); 512 | } 513 | if (Source.Length != 0) { 514 | output.WriteRawTag(34); 515 | output.WriteString(Source); 516 | } 517 | if (_unknownFields != null) { 518 | _unknownFields.WriteTo(output); 519 | } 520 | } 521 | 522 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 523 | public int CalculateSize() { 524 | int size = 0; 525 | size += logs_.CalculateSize(_repeated_logs_codec); 526 | if (ContextFlow.Length != 0) { 527 | size += 1 + pb::CodedOutputStream.ComputeStringSize(ContextFlow); 528 | } 529 | if (Filename.Length != 0) { 530 | size += 1 + pb::CodedOutputStream.ComputeStringSize(Filename); 531 | } 532 | if (Source.Length != 0) { 533 | size += 1 + pb::CodedOutputStream.ComputeStringSize(Source); 534 | } 535 | if (_unknownFields != null) { 536 | size += _unknownFields.CalculateSize(); 537 | } 538 | return size; 539 | } 540 | 541 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 542 | public void MergeFrom(LogGroup other) { 543 | if (other == null) { 544 | return; 545 | } 546 | logs_.Add(other.logs_); 547 | if (other.ContextFlow.Length != 0) { 548 | ContextFlow = other.ContextFlow; 549 | } 550 | if (other.Filename.Length != 0) { 551 | Filename = other.Filename; 552 | } 553 | if (other.Source.Length != 0) { 554 | Source = other.Source; 555 | } 556 | _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); 557 | } 558 | 559 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 560 | public void MergeFrom(pb::CodedInputStream input) { 561 | uint tag; 562 | while ((tag = input.ReadTag()) != 0) { 563 | switch(tag) { 564 | default: 565 | _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); 566 | break; 567 | case 10: { 568 | logs_.AddEntriesFrom(input, _repeated_logs_codec); 569 | break; 570 | } 571 | case 18: { 572 | ContextFlow = input.ReadString(); 573 | break; 574 | } 575 | case 26: { 576 | Filename = input.ReadString(); 577 | break; 578 | } 579 | case 34: { 580 | Source = input.ReadString(); 581 | break; 582 | } 583 | } 584 | } 585 | } 586 | 587 | } 588 | 589 | public sealed partial class LogGroupList : pb::IMessage { 590 | private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new LogGroupList()); 591 | private pb::UnknownFieldSet _unknownFields; 592 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 593 | public static pb::MessageParser Parser { get { return _parser; } } 594 | 595 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 596 | public static pbr::MessageDescriptor Descriptor { 597 | get { return global::TencentCloud.Cls.ClsReflection.Descriptor.MessageTypes[2]; } 598 | } 599 | 600 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 601 | pbr::MessageDescriptor pb::IMessage.Descriptor { 602 | get { return Descriptor; } 603 | } 604 | 605 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 606 | public LogGroupList() { 607 | OnConstruction(); 608 | } 609 | 610 | partial void OnConstruction(); 611 | 612 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 613 | public LogGroupList(LogGroupList other) : this() { 614 | logGroupList_ = other.logGroupList_.Clone(); 615 | _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); 616 | } 617 | 618 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 619 | public LogGroupList Clone() { 620 | return new LogGroupList(this); 621 | } 622 | 623 | /// Field number for the "logGroupList" field. 624 | public const int LogGroupList_FieldNumber = 1; 625 | private static readonly pb::FieldCodec _repeated_logGroupList_codec 626 | = pb::FieldCodec.ForMessage(10, global::TencentCloud.Cls.LogGroup.Parser); 627 | private readonly pbc::RepeatedField logGroupList_ = new pbc::RepeatedField(); 628 | /// 629 | /// 日志组列表 630 | /// 631 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 632 | public pbc::RepeatedField LogGroupList_ { 633 | get { return logGroupList_; } 634 | } 635 | 636 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 637 | public override bool Equals(object other) { 638 | return Equals(other as LogGroupList); 639 | } 640 | 641 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 642 | public bool Equals(LogGroupList other) { 643 | if (ReferenceEquals(other, null)) { 644 | return false; 645 | } 646 | if (ReferenceEquals(other, this)) { 647 | return true; 648 | } 649 | if(!logGroupList_.Equals(other.logGroupList_)) return false; 650 | return Equals(_unknownFields, other._unknownFields); 651 | } 652 | 653 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 654 | public override int GetHashCode() { 655 | int hash = 1; 656 | hash ^= logGroupList_.GetHashCode(); 657 | if (_unknownFields != null) { 658 | hash ^= _unknownFields.GetHashCode(); 659 | } 660 | return hash; 661 | } 662 | 663 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 664 | public override string ToString() { 665 | return pb::JsonFormatter.ToDiagnosticString(this); 666 | } 667 | 668 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 669 | public void WriteTo(pb::CodedOutputStream output) { 670 | logGroupList_.WriteTo(output, _repeated_logGroupList_codec); 671 | if (_unknownFields != null) { 672 | _unknownFields.WriteTo(output); 673 | } 674 | } 675 | 676 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 677 | public int CalculateSize() { 678 | int size = 0; 679 | size += logGroupList_.CalculateSize(_repeated_logGroupList_codec); 680 | if (_unknownFields != null) { 681 | size += _unknownFields.CalculateSize(); 682 | } 683 | return size; 684 | } 685 | 686 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 687 | public void MergeFrom(LogGroupList other) { 688 | if (other == null) { 689 | return; 690 | } 691 | logGroupList_.Add(other.logGroupList_); 692 | _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); 693 | } 694 | 695 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute] 696 | public void MergeFrom(pb::CodedInputStream input) { 697 | uint tag; 698 | while ((tag = input.ReadTag()) != 0) { 699 | switch(tag) { 700 | default: 701 | _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); 702 | break; 703 | case 10: { 704 | logGroupList_.AddEntriesFrom(input, _repeated_logGroupList_codec); 705 | break; 706 | } 707 | } 708 | } 709 | } 710 | 711 | } 712 | 713 | #endregion 714 | 715 | } 716 | 717 | #endregion Designer generated code 718 | --------------------------------------------------------------------------------