├── 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 |
--------------------------------------------------------------------------------