├── third-party
├── NLog.dll
└── RabbitMQ.Client.dll
├── src
├── CollectdWinService
│ ├── config
│ │ ├── Amqp.config
│ │ ├── WriteHttp.config
│ │ ├── Statsd.config
│ │ ├── CollectdWin.config
│ │ ├── nlog.config
│ │ ├── AmqpPluginConfig.cs
│ │ ├── WindowsPerformanceCounter.config
│ │ ├── WriteHttpPluginConfig.cs
│ │ ├── WindowsPerformanceCounterPluginConfig.cs
│ │ ├── StatsdPluginConfig.cs
│ │ └── CollectdWinConfig.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── ConsolePlugin.cs
│ ├── app.config
│ ├── CollectdWinService.cs
│ ├── Util.cs
│ ├── Program.cs
│ ├── PluginRegistry.cs
│ ├── StatsdListener.cs
│ ├── StatsdPlugin.cs
│ ├── Histogram.cs
│ ├── AmqpPlugin.cs
│ ├── MetricsPlugin.cs
│ ├── CollectdWinService.resx
│ ├── TypesDB.cs
│ ├── Aggregator.cs
│ ├── StatsdAggregator.cs
│ ├── CollectdWinService.csproj
│ ├── StatsdMetrics.cs
│ ├── MetricsCollector.cs
│ ├── types.db
│ └── WriteHttpPlugin.cs
├── CollectdWinTest
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── MetricValueTests.cs
│ └── CollectdWinTest.csproj
├── installer
│ ├── CollectdWin.wixproj
│ └── Product.wxs
└── CollectdWinService.sln
├── README.md
├── .gitignore
├── tools
└── version.py
├── CHANGELOG.md
└── LICENSE
/third-party/NLog.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloomberg/collectdwin/HEAD/third-party/NLog.dll
--------------------------------------------------------------------------------
/third-party/RabbitMQ.Client.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bloomberg/collectdwin/HEAD/third-party/RabbitMQ.Client.dll
--------------------------------------------------------------------------------
/src/CollectdWinService/config/Amqp.config:
--------------------------------------------------------------------------------
1 |
2 |
4 |
--------------------------------------------------------------------------------
/src/CollectdWinService/config/WriteHttp.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/CollectdWinService/config/Statsd.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CollectdWin
2 |
3 | CollectdWin is a MS Windows service which collects, aggregates and publishes both application and system metrics periodically. These application and system metrics can be used for performance analysis and capacity planning. CollectdWin is very similar to Collectd (https://collectd.org), it was developed because Collectd does not support Windows.
4 |
5 | For more info, refer [CollectdWin docs](../../wiki)
6 |
--------------------------------------------------------------------------------
/src/CollectdWinService/config/CollectdWin.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/CollectdWinService/config/nlog.config:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/CollectdWinService/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 |
8 | [assembly: AssemblyTitle("CollectdWinService")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Bloomberg LP")]
12 | [assembly: AssemblyProduct("CollectdWinService")]
13 | [assembly: AssemblyCopyright("Copyright © Bloomberg LP 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 |
21 | [assembly: ComVisible(false)]
22 |
23 | // The following GUID is for the ID of the typelib if this project is exposed to COM
24 |
25 | [assembly: Guid("dc0404f4-acd7-40b3-ab7a-6e63f023ac40")]
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // [assembly: AssemblyVersion("1.0.*")]
37 |
38 | [assembly: AssemblyVersion("0.5.19.0")]
39 | [assembly: AssemblyFileVersion("0.5.19.0")]
40 |
--------------------------------------------------------------------------------
/src/CollectdWinTest/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("CollectdWinTest")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Bloomberg LP")]
12 | [assembly: AssemblyProduct("CollectdWinTest")]
13 | [assembly: AssemblyCopyright("Copyright © Bloomberg LP 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("6f05d77a-f180-4779-95fe-75a5223417df")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/CollectdWinService/ConsolePlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NLog;
3 |
4 | namespace BloombergFLP.CollectdWin
5 | {
6 | internal class ConsolePlugin : IMetricsWritePlugin
7 | {
8 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
9 |
10 | public void Configure()
11 | {
12 | Logger.Info("console plugin configured");
13 | }
14 |
15 | public void Start()
16 | {
17 | Logger.Info("console plugin started");
18 | }
19 |
20 | public void Stop()
21 | {
22 | Logger.Info("console plugin stopped");
23 | }
24 |
25 | public void Write(MetricValue metric)
26 | {
27 | Console.WriteLine("ConsolePlugin: {0}", metric.GetMetricJsonStr());
28 | }
29 |
30 | public void Flush()
31 | {
32 | Console.WriteLine("ConsolePlugin: flushing");
33 | }
34 | }
35 | }
36 |
37 | // ----------------------------------------------------------------------------
38 | // Copyright (C) 2015 Bloomberg Finance L.P.
39 | //
40 | // Licensed under the Apache License, Version 2.0 (the "License");
41 | // you may not use this file except in compliance with the License.
42 | // You may obtain a copy of the License at
43 | // http://www.apache.org/licenses/LICENSE-2.0
44 | // Unless required by applicable law or agreed to in writing, software
45 | // distributed under the License is distributed on an "AS IS" BASIS,
46 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
47 | // See the License for the specific language governing permissions and
48 | // limitations under the License.
49 | //
50 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/CollectdWinService/CollectdWinService.cs:
--------------------------------------------------------------------------------
1 | using System.ServiceProcess;
2 | using NLog;
3 |
4 | namespace BloombergFLP.CollectdWin
5 | {
6 | public class CollectdWinService : ServiceBase
7 | {
8 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
9 | private MetricsCollector _metricsCollector;
10 |
11 | public CollectdWinService()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | protected override void OnStart(string[] args)
17 | {
18 | StartService(args);
19 | }
20 |
21 | protected override void OnStop()
22 | {
23 | StopService();
24 | }
25 |
26 | private void InitializeComponent()
27 | {
28 | ServiceName = "Bloomberg Metrics Collector Service";
29 | }
30 |
31 | // public accessibility for running as a console application
32 | public virtual void StartService(params string[] args)
33 | {
34 | Logger.Trace("StartService() begin");
35 | _metricsCollector = new MetricsCollector();
36 | _metricsCollector.ConfigureAll();
37 | _metricsCollector.StartAll();
38 | Logger.Trace("StartService() return");
39 | }
40 |
41 | // public accessibility for running as a console application
42 | public virtual void StopService()
43 | {
44 | Logger.Trace("StopService() begin");
45 | _metricsCollector.StopAll();
46 | Logger.Trace("StopService() return");
47 | }
48 | }
49 | }
50 |
51 | // ----------------------------------------------------------------------------
52 | // Copyright (C) 2015 Bloomberg Finance L.P.
53 | //
54 | // Licensed under the Apache License, Version 2.0 (the "License");
55 | // you may not use this file except in compliance with the License.
56 | // You may obtain a copy of the License at
57 | // http://www.apache.org/licenses/LICENSE-2.0
58 | // Unless required by applicable law or agreed to in writing, software
59 | // distributed under the License is distributed on an "AS IS" BASIS,
60 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
61 | // See the License for the specific language governing permissions and
62 | // limitations under the License.
63 | //
64 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/Util.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Configuration;
3 | using System.Net;
4 | using System.Net.Sockets;
5 | using NLog;
6 |
7 | namespace BloombergFLP.CollectdWin
8 | {
9 | public static class Util
10 | {
11 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
12 |
13 | public static double GetNow()
14 | {
15 | TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
16 | double epoch = t.TotalMilliseconds/1000;
17 | double now = Math.Round(epoch, 3);
18 | return (now);
19 | }
20 |
21 | public static string GetHostName()
22 | {
23 | string hostname = Environment.MachineName.ToLower();
24 | try
25 | {
26 | hostname = Dns.GetHostEntry("localhost").HostName.ToLower();
27 | }
28 | catch (SocketException)
29 | {
30 | Logger.Warn("Unable to resolve hostname, using MachineName: {0}", hostname);
31 | }
32 | var generalConfig = ConfigurationManager.GetSection("CollectdWinConfig") as CollectdWinConfig;
33 | if (generalConfig == null)
34 | {
35 | Logger.Error("Cannot get configuration section");
36 | return hostname;
37 | }
38 | if (! (String.IsNullOrEmpty(generalConfig.GeneralSettings.HostName)))
39 | {
40 | hostname = generalConfig.GeneralSettings.HostName;
41 | }
42 | return hostname;
43 | }
44 | }
45 | }
46 |
47 | // ----------------------------------------------------------------------------
48 | // Copyright (C) 2015 Bloomberg Finance L.P.
49 | //
50 | // Licensed under the Apache License, Version 2.0 (the "License");
51 | // you may not use this file except in compliance with the License.
52 | // You may obtain a copy of the License at
53 | // http://www.apache.org/licenses/LICENSE-2.0
54 | // Unless required by applicable law or agreed to in writing, software
55 | // distributed under the License is distributed on an "AS IS" BASIS,
56 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
57 | // See the License for the specific language governing permissions and
58 | // limitations under the License.
59 | //
60 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Configuration;
3 | using System.ServiceProcess;
4 | using NLog;
5 |
6 | namespace BloombergFLP.CollectdWin
7 | {
8 | public static class Program
9 | {
10 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
11 |
12 | ///
13 | /// The main entry point for the application.
14 | ///
15 | public static void Main(string[] args)
16 | {
17 | var config = ConfigurationManager.GetSection("CollectdWinConfig") as CollectdWinConfig;
18 | if (config == null)
19 | {
20 | Logger.Error("Main(): cannot get configuration section");
21 | return;
22 | }
23 |
24 | var collectdWinService = new CollectdWinService();
25 |
26 | if (Array.Find(args, s => s.Equals(@"console")) != null)
27 | {
28 | Console.WriteLine("*** Starting CollectdWin in console mode***");
29 | // run as a console application for testing and debugging purpose
30 | collectdWinService.StartService();
31 | Console.WriteLine("*** Enter Ctrl-C to exit: ***");
32 | Console.ReadLine();
33 | }
34 | else
35 | {
36 | // run as a windows service
37 | ServiceBase[] servicesToRun = {collectdWinService};
38 | ServiceBase.Run(servicesToRun);
39 | }
40 | Logger.Error("CollectdWin: exiting ...");
41 | }
42 | }
43 | }
44 |
45 | // ----------------------------------------------------------------------------
46 | // Copyright (C) 2015 Bloomberg Finance L.P.
47 | //
48 | // Licensed under the Apache License, Version 2.0 (the "License");
49 | // you may not use this file except in compliance with the License.
50 | // You may obtain a copy of the License at
51 | // http://www.apache.org/licenses/LICENSE-2.0
52 | // Unless required by applicable law or agreed to in writing, software
53 | // distributed under the License is distributed on an "AS IS" BASIS,
54 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
55 | // See the License for the specific language governing permissions and
56 | // limitations under the License.
57 | //
58 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinTest/MetricValueTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 | using BloombergFLP.CollectdWin;
4 |
5 | namespace BloombergFLP.CollectdWinTest
6 | {
7 | [TestClass]
8 | public class MetricValueTests
9 | {
10 | private MetricValue val1, val2;
11 | private string val1Str, val2Str;
12 |
13 |
14 | public MetricValueTests()
15 | {
16 | initTest();
17 | }
18 |
19 | private void initTest()
20 | {
21 | val1 = new MetricValue
22 | {
23 | HostName = "host-1",
24 | PluginName = "cpu",
25 | PluginInstanceName = "",
26 | TypeName = "percent",
27 | TypeInstanceName = "",
28 | Values = new double[] { 123.0 }
29 | };
30 | val1Str = @"{""host"":""host-1"", ""plugin"":""cpu"", ""plugin_instance"":"""", ""type"":""percent"", " +
31 | @"""type_instance"":"""", ""time"":0, ""interval"":0, ""dstypes"":[""gauge""], ""dsnames"":[""value""], ""values"":[123]}";
32 | val2 = new MetricValue
33 | {
34 | HostName = "host-2",
35 | PluginName = "cpu",
36 | PluginInstanceName = "",
37 | TypeName = "percent",
38 | TypeInstanceName = "",
39 | Values = new double[] { 123.0 },
40 | };
41 | val2.AddMetaData("region", "ny");
42 | val2.AddMetaData("dc", "datacenter-1");
43 | val2Str = @"{""host"":""host-2"", ""plugin"":""cpu"", ""plugin_instance"":"""", ""type"":""percent"", " +
44 | @"""type_instance"":"""", ""time"":0, ""interval"":0, ""dstypes"":[""gauge""], ""dsnames"":[""value""], ""values"":[123]" +
45 | @", ""meta"":{""dc"":""datacenter-1"",""region"":""ny""}}";
46 | }
47 |
48 | [TestMethod]
49 | public void MetricWithEmptyTags()
50 | {
51 | string expected = val1.GetMetricJsonStr();
52 | Assert.AreEqual(expected, val1Str, "MetricWithEmptyTags failed");
53 | }
54 |
55 | [TestMethod]
56 | public void MetricWithTwoTags()
57 | {
58 | string expected = val2.GetMetricJsonStr();
59 | Assert.AreEqual(expected, val2Str, "MetricWithTwoTags failed");
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/src/installer/CollectdWin.wixproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 3.9
7 | 93cc9e80-b6f5-4768-998e-889bdf5ab579
8 | 2.0
9 | CollectdWin-$(Platform)
10 | Package
11 | $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets
12 | $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets
13 | CollectdWin
14 |
15 |
16 | bin\$(Platform)\$(Configuration)\
17 | obj\$(Platform)\$(Configuration)\
18 | Debug
19 |
20 |
21 | bin\$(Platform)\$(Configuration)\
22 | obj\$(Platform)\$(Configuration)\
23 |
24 |
25 | Debug
26 | bin\$(Platform)\$(Configuration)\
27 | obj\$(Platform)\$(Configuration)\
28 |
29 |
30 | bin\$(Platform)\$(Configuration)\
31 | obj\$(Platform)\$(Configuration)\
32 |
33 |
34 |
35 |
36 |
37 |
45 |
46 |
--------------------------------------------------------------------------------
/src/CollectdWinService/PluginRegistry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using NLog;
6 |
7 | namespace BloombergFLP.CollectdWin
8 | {
9 | internal class PluginRegistry
10 | {
11 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
12 |
13 | private readonly Dictionary _registry = new Dictionary();
14 |
15 | public PluginRegistry()
16 | {
17 | var config = ConfigurationManager.GetSection("CollectdWinConfig") as CollectdWinConfig;
18 | if (config == null)
19 | {
20 | Logger.Error("Cannot get configuration section : CollectdWinConfig");
21 | return;
22 | }
23 | foreach (
24 | CollectdWinConfig.PluginConfig pluginConfig in
25 | config.Plugins.Cast()
26 | .Where(pluginConfig => pluginConfig.Enable))
27 | {
28 | _registry[pluginConfig.Name] = pluginConfig.Class;
29 | }
30 | }
31 |
32 | public IList CreatePlugins()
33 | {
34 | IList plugins = new List();
35 | foreach (var entry in _registry)
36 | {
37 | Type classType = Type.GetType(entry.Value);
38 | if (classType == null)
39 | {
40 | Logger.Error("Cannot create plugin:{0}, class:{1}", entry.Key, entry.Value);
41 | continue;
42 | }
43 | var plugin = (IMetricsPlugin) Activator.CreateInstance(classType);
44 | plugins.Add(plugin);
45 | }
46 | return (plugins);
47 | }
48 | }
49 | }
50 |
51 | // ----------------------------------------------------------------------------
52 | // Copyright (C) 2015 Bloomberg Finance L.P.
53 | //
54 | // Licensed under the Apache License, Version 2.0 (the "License");
55 | // you may not use this file except in compliance with the License.
56 | // You may obtain a copy of the License at
57 | // http://www.apache.org/licenses/LICENSE-2.0
58 | // Unless required by applicable law or agreed to in writing, software
59 | // distributed under the License is distributed on an "AS IS" BASIS,
60 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
61 | // See the License for the specific language governing permissions and
62 | // limitations under the License.
63 | //
64 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/.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 | *.sln.docstates
8 | src/CollectdWinService.userprefs
9 |
10 | # Build results
11 |
12 | [Dd]ebug/
13 | [Rr]elease/
14 | x64/
15 | build/
16 | [Bb]in/
17 | [Oo]bj/
18 |
19 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
20 | !packages/*/build/
21 |
22 | # MSTest test Results
23 | [Tt]est[Rr]esult*/
24 | [Bb]uild[Ll]og.*
25 |
26 | *_i.c
27 | *_p.c
28 | *.ilk
29 | *.meta
30 | *.obj
31 | *.pch
32 | *.pdb
33 | *.pgc
34 | *.pgd
35 | *.rsp
36 | *.sbr
37 | *.tlb
38 | *.tli
39 | *.tlh
40 | *.tmp
41 | *.tmp_proj
42 | *.log
43 | *.vspscc
44 | *.vssscc
45 | .builds
46 | *.pidb
47 | *.log
48 | *.scc
49 |
50 | # Visual C++ cache files
51 | ipch/
52 | *.aps
53 | *.ncb
54 | *.opensdf
55 | *.sdf
56 | *.cachefile
57 |
58 | # Visual Studio profiler
59 | *.psess
60 | *.vsp
61 | *.vspx
62 |
63 | # Guidance Automation Toolkit
64 | *.gpState
65 |
66 | # ReSharper is a .NET coding add-in
67 | _ReSharper*/
68 | *.[Rr]e[Ss]harper
69 |
70 | # TeamCity is a build add-in
71 | _TeamCity*
72 |
73 | # DotCover is a Code Coverage Tool
74 | *.dotCover
75 |
76 | # NCrunch
77 | *.ncrunch*
78 | .*crunch*.local.xml
79 |
80 | # Installshield output folder
81 | [Ee]xpress/
82 |
83 | # DocProject is a documentation generator add-in
84 | DocProject/buildhelp/
85 | DocProject/Help/*.HxT
86 | DocProject/Help/*.HxC
87 | DocProject/Help/*.hhc
88 | DocProject/Help/*.hhk
89 | DocProject/Help/*.hhp
90 | DocProject/Help/Html2
91 | DocProject/Help/html
92 |
93 | # Click-Once directory
94 | publish/
95 |
96 | # Publish Web Output
97 | *.Publish.xml
98 |
99 | # NuGet Packages Directory
100 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
101 | #packages/
102 |
103 | # Windows Azure Build Output
104 | csx
105 | *.build.csdef
106 |
107 | # Windows Store app package directory
108 | AppPackages/
109 |
110 | # Others
111 | sql/
112 | *.Cache
113 | ClientBin/
114 | [Ss]tyle[Cc]op.*
115 | ~$*
116 | *~
117 | *.dbmdl
118 | *.[Pp]ublish.xml
119 | *.pfx
120 | *.publishsettings
121 |
122 | # RIA/Silverlight projects
123 | Generated_Code/
124 |
125 | # Backup & report files from converting an old project file to a newer
126 | # Visual Studio version. Backup files are not needed, because we have git ;-)
127 | _UpgradeReport_Files/
128 | Backup*/
129 | UpgradeLog*.XML
130 | UpgradeLog*.htm
131 |
132 | # SQL Server files
133 | App_Data/*.mdf
134 | App_Data/*.ldf
135 |
136 |
137 | #LightSwitch generated files
138 | GeneratedArtifacts/
139 | _Pvt_Extensions/
140 | ModelManifest.xml
141 |
142 | # =========================
143 | # Windows detritus
144 | # =========================
145 |
146 | # Windows image file caches
147 | Thumbs.db
148 | ehthumbs.db
149 |
150 | # Folder config file
151 | Desktop.ini
152 |
153 | # Recycle Bin used on file shares
154 | $RECYCLE.BIN/
155 |
156 | # Mac desktop service store files
157 | .DS_Store
158 |
159 | # IntelliJ IDEA
160 | .idea
161 |
--------------------------------------------------------------------------------
/tools/version.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import fileinput
3 | import re
4 | import sys
5 |
6 | #
7 | # This script gets or updates version number. Version number
8 | # is in AssemblyInfo.cs with the following format:
9 | # ...
10 | #
11 | # Example:
12 | # [assembly: AssemblyVersion("0.5.3.0")]
13 | # [assembly: AssemblyFileVersion("0.5.3.0")]
14 | #
15 |
16 | def usage(parser) :
17 | parser.print_help()
18 | sys.exit(1);
19 |
20 | def main( ) :
21 | VERSION_FILE = 'src\CollectdWinService\Properties\AssemblyInfo.cs'
22 | VERSION_FORMAT = "{0}.{1}.{2}.{3}"
23 | VERSION_PATTERN = '^\[assembly: AssemblyVersion\(\"(\d+).(\d+).(\d+).(\d+)\"\)\]'
24 | REPLACE_PATTERN = r"(^\[assembly: Assembly.*Version\(\").*(\"\)\])"
25 | REPLACE_FORMAT = r"\g<1>{0}\g<2>"
26 |
27 | parser = argparse.ArgumentParser()
28 | parser.add_argument("--command", help="get|update")
29 | parser.add_argument("--part", help="major|minor|build|revision")
30 | args = parser.parse_args()
31 |
32 | vfile = open(VERSION_FILE)
33 | for line in vfile:
34 | m = re.match(VERSION_PATTERN, line)
35 | if m:
36 | cmajor = int(m.group(1))
37 | cminor = int(m.group(2))
38 | cbuild = int(m.group(3))
39 | crevision = int(m.group(4))
40 | cversion = VERSION_FORMAT.format(cmajor, cminor, cbuild, crevision)
41 |
42 | vfile.close()
43 | if args.command == "get" :
44 | print(cversion)
45 | sys.exit(0)
46 | elif args.command != "update" :
47 | print("\nError: Missing or bad COMMAND\n")
48 | usage(parser)
49 |
50 | if args.part == "major" :
51 | nmajor = cmajor + 1
52 | nminor = 0
53 | nbuild = 0
54 | nrevision = 0
55 | elif args.part == "minor" :
56 | nmajor = cmajor
57 | nminor = cminor + 1
58 | nbuild = 0
59 | nrevision = 0
60 | elif args.part == "build" :
61 | nmajor = cmajor
62 | nminor = cminor
63 | nbuild = cbuild + 1
64 | nrevision = 0
65 | elif args.part == "revision" :
66 | nmajor = cmajor
67 | nminor = cminor
68 | nbuild = cbuild
69 | nrevision = crevision + 1
70 | else :
71 | print("\nError: Missing or bad PART\n")
72 | usage(parser)
73 |
74 | nversion = VERSION_FORMAT.format(nmajor, nminor, nbuild, nrevision)
75 |
76 | for line in fileinput.input(files=[VERSION_FILE], inplace=1, backup='.bak'):
77 | line = re.sub(REPLACE_PATTERN, REPLACE_FORMAT.format(nversion), line.rstrip())
78 | print(line)
79 |
80 |
81 | if __name__ == "__main__":
82 | main( )
83 |
84 |
85 | #-----------------------------------------------------------------------------
86 | # Copyright (C) 2015 Bloomberg Finance L.P.
87 | #
88 | # Licensed under the Apache License, Version 2.0 (the "License");
89 | # you may not use this file except in compliance with the License.
90 | # You may obtain a copy of the License at
91 | # http://www.apache.org/licenses/LICENSE-2.0
92 | # Unless required by applicable law or agreed to in writing, software
93 | # distributed under the License is distributed on an "AS IS" BASIS,
94 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
95 | # See the License for the specific language governing permissions and
96 | # limitations under the License.
97 | #
98 | #------------------------------ END-OF-FILE ----------------------------------
99 |
--------------------------------------------------------------------------------
/src/CollectdWinService/config/AmqpPluginConfig.cs:
--------------------------------------------------------------------------------
1 | using System.Configuration;
2 |
3 | namespace BloombergFLP.CollectdWin
4 | {
5 | internal class AmqpPluginConfig : ConfigurationSection
6 | {
7 | [ConfigurationProperty("Publish", IsRequired = false)]
8 | public PublishConfig Publish
9 | {
10 | get { return (PublishConfig) base["Publish"]; }
11 | set { base["Publish"] = value; }
12 | }
13 |
14 | public static AmqpPluginConfig GetConfig()
15 | {
16 | return (AmqpPluginConfig) ConfigurationManager.GetSection("Amqp") ?? new AmqpPluginConfig();
17 | }
18 |
19 | public sealed class PublishConfig : ConfigurationElement
20 | {
21 | [ConfigurationProperty("Name", IsRequired = true)]
22 | public string Name
23 | {
24 | get { return (string) base["Name"]; }
25 | set { base["Name"] = value; }
26 | }
27 |
28 | [ConfigurationProperty("Host", IsRequired = false)]
29 | public string Host
30 | {
31 | get { return (string) base["Host"]; }
32 | set { base["Host"] = value; }
33 | }
34 |
35 | [ConfigurationProperty("Port", IsRequired = true)]
36 | public int Port
37 | {
38 | get { return (int) base["Port"]; }
39 | set { base["Port"] = value; }
40 | }
41 |
42 | [ConfigurationProperty("VirtualHost", IsRequired = false)]
43 | public string VirtualHost
44 | {
45 | get { return (string) base["VirtualHost"]; }
46 | set { base["VirtualHost"] = value; }
47 | }
48 |
49 | [ConfigurationProperty("User", IsRequired = false)]
50 | public string User
51 | {
52 | get { return (string) base["User"]; }
53 | set { base["User"] = value; }
54 | }
55 |
56 | [ConfigurationProperty("Password", IsRequired = false)]
57 | public string Password
58 | {
59 | get { return (string) base["Password"]; }
60 | set { base["Password"] = value; }
61 | }
62 |
63 | [ConfigurationProperty("Exchange", IsRequired = false)]
64 | public string Exchange
65 | {
66 | get { return (string) base["Exchange"]; }
67 | set { base["Exchange"] = value; }
68 | }
69 |
70 | [ConfigurationProperty("RoutingKeyPrefix", IsRequired = false)]
71 | public string RoutingKeyPrefix
72 | {
73 | get { return (string) base["RoutingKeyPrefix"]; }
74 | set { base["RoutingKeyPrefix"] = value; }
75 | }
76 | }
77 | }
78 | }
79 |
80 | // ----------------------------------------------------------------------------
81 | // Copyright (C) 2015 Bloomberg Finance L.P.
82 | //
83 | // Licensed under the Apache License, Version 2.0 (the "License");
84 | // you may not use this file except in compliance with the License.
85 | // You may obtain a copy of the License at
86 | // http://www.apache.org/licenses/LICENSE-2.0
87 | // Unless required by applicable law or agreed to in writing, software
88 | // distributed under the License is distributed on an "AS IS" BASIS,
89 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
90 | // See the License for the specific language governing permissions and
91 | // limitations under the License.
92 | //
93 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/StatsdListener.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Net.Sockets;
4 | using System.Text;
5 | using System.Threading;
6 | using NLog;
7 |
8 | namespace BloombergFLP.CollectdWin
9 | {
10 | internal class StatsdListener
11 | {
12 | public delegate void HandleMessage(string message);
13 |
14 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
15 |
16 | private readonly IPEndPoint _endPoint;
17 |
18 | private readonly HandleMessage _messageHandler;
19 | private readonly Socket _socket;
20 | private bool _run;
21 |
22 | public StatsdListener(int port, HandleMessage handleMessage)
23 | {
24 | _messageHandler = handleMessage;
25 | _endPoint = new IPEndPoint(IPAddress.Any, port);
26 | _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
27 | }
28 |
29 | private void BindSocket()
30 | {
31 | while (!_socket.IsBound)
32 | {
33 | try
34 | {
35 | _socket.Bind(_endPoint);
36 | }
37 | catch (Exception exp)
38 | {
39 | Logger.Error("BindSocket failed: ", exp);
40 | }
41 | if (_socket.IsBound)
42 | break;
43 | Thread.Sleep(10*1000);
44 | }
45 | }
46 |
47 | private void CloseSocket()
48 | {
49 | try
50 | {
51 | _socket.Shutdown(SocketShutdown.Both);
52 | _socket.Close();
53 | }
54 | catch (Exception exp)
55 | {
56 | Logger.Error("CloseSocket failed: ", exp);
57 | }
58 | }
59 |
60 | public void Start()
61 | {
62 | Logger.Trace("Start() begin");
63 | var buffer = new byte[1024*4];
64 |
65 | var sender = new IPEndPoint(IPAddress.Any, 0);
66 | EndPoint remote = sender;
67 |
68 | _run = true;
69 | while (_run)
70 | {
71 | if (!_socket.IsBound)
72 | {
73 | BindSocket();
74 | }
75 | try
76 | {
77 | int recv = _socket.ReceiveFrom(buffer, ref remote);
78 | string str = Encoding.ASCII.GetString(buffer, 0, recv);
79 | str = str.TrimEnd('\r', '\n');
80 |
81 | _messageHandler(str);
82 | }
83 | catch
84 | {
85 | CloseSocket();
86 | }
87 | }
88 |
89 | Logger.Trace("Start() end");
90 | }
91 |
92 | public void Stop()
93 | {
94 | Logger.Trace("Stop() begin");
95 | _run = false;
96 | // closing socket will cause Socket.ReceiveFrom() blocked call to
97 | // throw SocketException, a work-around for shutting down a listener.
98 | CloseSocket();
99 | Logger.Trace("Stop() end");
100 | }
101 | }
102 | }
103 |
104 | // ----------------------------------------------------------------------------
105 | // Copyright (C) 2015 Bloomberg Finance L.P.
106 | //
107 | // Licensed under the Apache License, Version 2.0 (the "License");
108 | // you may not use this file except in compliance with the License.
109 | // You may obtain a copy of the License at
110 | // http://www.apache.org/licenses/LICENSE-2.0
111 | // Unless required by applicable law or agreed to in writing, software
112 | // distributed under the License is distributed on an "AS IS" BASIS,
113 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
114 | // See the License for the specific language governing permissions and
115 | // limitations under the License.
116 | //
117 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/StatsdPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Threading;
6 | using NLog;
7 |
8 | namespace BloombergFLP.CollectdWin
9 | {
10 | internal class StatsdPlugin : IMetricsReadPlugin
11 | {
12 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
13 | private bool _delCounters;
14 | private bool _delGauges, _delSets;
15 | private bool _delTimers;
16 | private float[] _percentiles;
17 | private int _port;
18 | private bool _running;
19 | private StatsdAggregator _statsdAggregator;
20 | private StatsdListener _statsdListener;
21 | private Thread _statsdThread;
22 | private bool _timerCount;
23 | private bool _timerLower;
24 | private bool _timerSum;
25 | private bool _timerUpper;
26 |
27 | public StatsdPlugin()
28 | {
29 | _running = false;
30 | }
31 |
32 | public void Configure()
33 | {
34 | var config = ConfigurationManager.GetSection("Statsd") as StatsdPluginConfig;
35 | if (config == null)
36 | {
37 | throw new Exception("Cannot get configuration section : Statsd");
38 | }
39 |
40 | _port = config.Server.Port;
41 |
42 | _delCounters = config.DeleteCache.Counters;
43 | _delTimers = config.DeleteCache.Timers;
44 | _delGauges = config.DeleteCache.Gauges;
45 | _delSets = config.DeleteCache.Sets;
46 |
47 | _timerLower = config.Timer.Lower;
48 | _timerUpper = config.Timer.Upper;
49 | _timerSum = config.Timer.Sum;
50 | _timerCount = config.Timer.Count;
51 | _percentiles =
52 | (from StatsdPluginConfig.PercentileConfig percentileConfig in
53 | config.Timer.Percentiles
54 | select percentileConfig.Value).ToArray();
55 |
56 | _statsdAggregator = new StatsdAggregator(_delCounters, _delTimers, _delGauges, _delSets, _timerLower,
57 | _timerUpper,
58 | _timerSum, _timerCount, _percentiles);
59 | Logger.Info("Statsd plugin configured");
60 | }
61 |
62 | public void Start()
63 | {
64 | if (_running)
65 | return;
66 |
67 | _statsdListener = new StatsdListener(_port, HandleMessage);
68 | _statsdThread = new Thread(_statsdListener.Start);
69 | _statsdThread.Start();
70 |
71 | _running = true;
72 | Logger.Info("Statsd plugin started");
73 | }
74 |
75 | public void Stop()
76 | {
77 | if (!_running)
78 | return;
79 | _statsdListener.Stop();
80 | _statsdThread.Interrupt();
81 |
82 | _running = false;
83 | Logger.Info("Statsd plugin stopped");
84 | }
85 |
86 | public IList Read()
87 | {
88 | return (_statsdAggregator.Read());
89 | }
90 |
91 | public void HandleMessage(string message)
92 | {
93 | IList metrics = StatsdMetricParser.Parse(message);
94 | foreach (StatsdMetric metric in metrics)
95 | {
96 | _statsdAggregator.AddMetric(metric);
97 | }
98 | }
99 | }
100 | }
101 |
102 | // ----------------------------------------------------------------------------
103 | // Copyright (C) 2015 Bloomberg Finance L.P.
104 | //
105 | // Licensed under the Apache License, Version 2.0 (the "License");
106 | // you may not use this file except in compliance with the License.
107 | // You may obtain a copy of the License at
108 | // http://www.apache.org/licenses/LICENSE-2.0
109 | // Unless required by applicable law or agreed to in writing, software
110 | // distributed under the License is distributed on an "AS IS" BASIS,
111 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
112 | // See the License for the specific language governing permissions and
113 | // limitations under the License.
114 | //
115 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/Histogram.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NLog;
3 |
4 | namespace BloombergFLP.CollectdWin
5 | {
6 | internal class Histogram
7 | {
8 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
9 | private readonly int[] _bins;
10 | private readonly int _numBins;
11 | private int _binSize;
12 | private double _max;
13 | private double _min;
14 | private int _num;
15 | private double _sum;
16 |
17 | public Histogram()
18 | {
19 | _min = _max = _sum = _num = 0;
20 | _numBins = 100;
21 | _bins = new int[100];
22 | _binSize = 8;
23 | }
24 |
25 | private int GetBin(double val)
26 | {
27 | var bin = (int) (val/_binSize);
28 | return (bin);
29 | }
30 |
31 | public void Resize(double val)
32 | {
33 | double requiredBinSize = val/_numBins;
34 | // to reduce frequent resizing, new bin size will be the the next nearest power of 2
35 | // eg: 16, 32, 64, 128, 256, 512, 1024, 2048, 5086
36 | var newBinSize = (int) Math.Pow(2, Math.Ceiling(Math.Log(requiredBinSize, 2)));
37 | int oldBinSize = _binSize;
38 | for (int i = 1; i < _numBins; i++)
39 | {
40 | val = i*oldBinSize;
41 | int newBin = (int) val/newBinSize;
42 | if (i == newBin)
43 | continue;
44 | _bins[newBin] += _bins[i];
45 | _bins[i] = 0;
46 | }
47 | _binSize = newBinSize;
48 | Logger.Debug("Resize() - OldBinSize:{0} has been replaced with the NewBinSize:{1}", oldBinSize, newBinSize);
49 | }
50 |
51 | public void AddValue(double val)
52 | {
53 | int bin = GetBin(val);
54 | if (bin >= _numBins)
55 | {
56 | Resize(val);
57 | bin = GetBin(val);
58 | Logger.Debug("Got new bin:{0}", bin);
59 | }
60 | _bins[bin]++;
61 |
62 | _min = (_min > val) ? val : _min;
63 | _max = (_max < val) ? val : _max;
64 | _sum += val;
65 | _num++;
66 | }
67 |
68 | public double GetPercentile(float percent)
69 | {
70 | double percentUpper = 0;
71 | double percentLower = 0;
72 | double sum = 0;
73 |
74 | if (percent < 0 || percent > 100 || _num <= 0)
75 | return (0);
76 |
77 | int i;
78 | for (i = 0; i < _numBins; i++)
79 | {
80 | percentLower = percentUpper;
81 | sum += _bins[i];
82 | percentUpper = 100*(sum/_num);
83 | if (percentUpper >= percent)
84 | break;
85 | }
86 | if (Math.Abs(percentUpper) < 0.01 || i >= _numBins)
87 | return (0);
88 | double valLower = i*_binSize;
89 | double valUpper = (i + 1)*_binSize;
90 |
91 | double val = (((percentUpper - percent)*valLower) + ((percent - percentLower)*valUpper))/
92 | (percentUpper - percentLower);
93 |
94 | return (val);
95 | }
96 |
97 | public void Reset()
98 | {
99 | _min = _max = _sum = _num = 0;
100 | for (int i = 0; i < _numBins; i++)
101 | _bins[i] = 0;
102 | }
103 |
104 | public override string ToString()
105 | {
106 | String logstr = String.Format("Min:{0} Max:{1} Sum{2} Num{3}", _min, _max, _sum, _num);
107 | for (int i = 0; i < _numBins; i++)
108 | logstr += ", " + _bins[i];
109 | return (logstr);
110 | }
111 | }
112 | }
113 |
114 | // ----------------------------------------------------------------------------
115 | // Copyright (C) 2015 Bloomberg Finance L.P.
116 | //
117 | // Licensed under the Apache License, Version 2.0 (the "License");
118 | // you may not use this file except in compliance with the License.
119 | // You may obtain a copy of the License at
120 | // http://www.apache.org/licenses/LICENSE-2.0
121 | // Unless required by applicable law or agreed to in writing, software
122 | // distributed under the License is distributed on an "AS IS" BASIS,
123 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124 | // See the License for the specific language governing permissions and
125 | // limitations under the License.
126 | //
127 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/config/WindowsPerformanceCounter.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
8 |
10 |
12 |
14 |
15 |
17 |
20 |
22 |
24 |
25 |
27 |
28 |
31 |
32 |
34 |
36 |
37 |
39 |
41 |
43 |
44 |
46 |
47 |
50 |
51 |
54 |
55 |
58 |
59 |
61 |
62 |
64 |
66 |
68 |
69 |
--------------------------------------------------------------------------------
/src/CollectdWinService.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.23107.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CollectdWinService", "CollectdWinService\CollectdWinService.csproj", "{D4244E6B-84EC-41A0-96A7-4F489F6098BC}"
7 | EndProject
8 | Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "CollectdWin", "installer\CollectdWin.wixproj", "{93CC9E80-B6F5-4768-998E-889BDF5AB579}"
9 | ProjectSection(ProjectDependencies) = postProject
10 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC} = {D4244E6B-84EC-41A0-96A7-4F489F6098BC}
11 | EndProjectSection
12 | EndProject
13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CollectdWinTest", "CollectdWinTest\CollectdWinTest.csproj", "{6F05D77A-F180-4779-95FE-75A5223417DF}"
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Debug|Mixed Platforms = Debug|Mixed Platforms
19 | Debug|x64 = Debug|x64
20 | Debug|x86 = Debug|x86
21 | Release|Any CPU = Release|Any CPU
22 | Release|Mixed Platforms = Release|Mixed Platforms
23 | Release|x64 = Release|x64
24 | Release|x86 = Release|x86
25 | EndGlobalSection
26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
27 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
30 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Debug|Mixed Platforms.Build.0 = Debug|x86
31 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Debug|Mixed Platforms.Deploy.0 = Debug|x86
32 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Debug|x64.ActiveCfg = Debug|x64
33 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Debug|x64.Build.0 = Debug|x64
34 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Debug|x64.Deploy.0 = Debug|x64
35 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Debug|x86.ActiveCfg = Debug|x86
36 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Debug|x86.Build.0 = Debug|x86
37 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Debug|x86.Deploy.0 = Debug|x86
38 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Release|Mixed Platforms.ActiveCfg = Release|x86
41 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Release|Mixed Platforms.Build.0 = Release|x86
42 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Release|x64.ActiveCfg = Release|x64
43 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Release|x64.Build.0 = Release|x64
44 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Release|x86.ActiveCfg = Release|x86
45 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}.Release|x86.Build.0 = Release|x86
46 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Debug|Any CPU.ActiveCfg = Debug|x86
47 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
48 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Debug|Mixed Platforms.Build.0 = Debug|x86
49 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Debug|x64.ActiveCfg = Debug|x64
50 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Debug|x64.Build.0 = Debug|x64
51 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Debug|x86.ActiveCfg = Debug|x86
52 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Debug|x86.Build.0 = Debug|x86
53 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Release|Any CPU.ActiveCfg = Release|x86
54 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Release|Mixed Platforms.ActiveCfg = Release|x86
55 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Release|Mixed Platforms.Build.0 = Release|x86
56 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Release|x64.ActiveCfg = Release|x64
57 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Release|x64.Build.0 = Release|x64
58 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Release|x86.ActiveCfg = Release|x86
59 | {93CC9E80-B6F5-4768-998E-889BDF5AB579}.Release|x86.Build.0 = Release|x86
60 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
61 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
62 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
63 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
64 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Debug|x64.ActiveCfg = Debug|x64
65 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Debug|x64.Build.0 = Debug|x64
66 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Debug|x86.ActiveCfg = Debug|Any CPU
67 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Debug|x86.Build.0 = Debug|Any CPU
68 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
69 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Release|Any CPU.Build.0 = Release|Any CPU
70 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
71 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Release|Mixed Platforms.Build.0 = Release|Any CPU
72 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Release|x64.ActiveCfg = Release|Any CPU
73 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Release|x64.Build.0 = Release|Any CPU
74 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Release|x86.ActiveCfg = Release|Any CPU
75 | {6F05D77A-F180-4779-95FE-75A5223417DF}.Release|x86.Build.0 = Release|Any CPU
76 | EndGlobalSection
77 | GlobalSection(SolutionProperties) = preSolution
78 | HideSolutionNode = FALSE
79 | EndGlobalSection
80 | EndGlobal
81 |
--------------------------------------------------------------------------------
/src/CollectdWinTest/CollectdWinTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {6F05D77A-F180-4779-95FE-75A5223417DF}
7 | Library
8 | Properties
9 | CollectdWinTest
10 | CollectdWinTest
11 | v3.5
12 | 512
13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 10.0
15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
17 | False
18 | UnitTest
19 |
20 |
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 | x64
29 |
30 |
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 | x64
40 | bin\x64\Debug\
41 |
42 |
43 | x64
44 | bin\x64\Release\
45 |
46 |
47 |
48 |
49 | 3.5
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | {d4244e6b-84ec-41a0-96a7-4f489f6098bc}
71 | CollectdWinService
72 |
73 |
74 |
75 |
76 |
77 |
78 | False
79 |
80 |
81 | False
82 |
83 |
84 | False
85 |
86 |
87 | False
88 |
89 |
90 |
91 |
92 |
93 |
94 |
101 |
--------------------------------------------------------------------------------
/src/CollectdWinService/config/WriteHttpPluginConfig.cs:
--------------------------------------------------------------------------------
1 | using System.Configuration;
2 |
3 | namespace BloombergFLP.CollectdWin
4 | {
5 | internal class WriteHttpPluginConfig : ConfigurationSection
6 | {
7 | [ConfigurationProperty("Nodes", IsRequired = false)]
8 | [ConfigurationCollection(typeof (WriteHttpNodeConfigCollection), AddItemName = "Node")]
9 | public WriteHttpNodeConfigCollection Nodes
10 | {
11 | get { return (WriteHttpNodeConfigCollection) base["Nodes"]; }
12 | set { base["Nodes"] = value; }
13 | }
14 |
15 | public static WriteHttpPluginConfig GetConfig()
16 | {
17 | return (WriteHttpPluginConfig) ConfigurationManager.GetSection("WriteHttp") ?? new WriteHttpPluginConfig();
18 | }
19 |
20 | public sealed class WriteHttpNodeConfig : ConfigurationElement
21 | {
22 | [ConfigurationProperty("Name", IsRequired = true)]
23 | public string Name
24 | {
25 | get { return (string) base["Name"]; }
26 | set { base["Name"] = value; }
27 | }
28 |
29 | [ConfigurationProperty("Url", IsRequired = true)]
30 | public string Url
31 | {
32 | get { return (string) base["Url"]; }
33 | set { base["Url"] = value; }
34 | }
35 |
36 | [ConfigurationProperty("Timeout", IsRequired = true)]
37 | public int Timeout
38 | {
39 | get { return (int) base["Timeout"]; }
40 | set { base["Timeout"] = value; }
41 | }
42 |
43 | [ConfigurationProperty("BatchSize", IsRequired = true)]
44 | public int BatchSize
45 | {
46 | get { return (int) base["BatchSize"]; }
47 | set { base["BatchSize"] = value; }
48 | }
49 |
50 | [ConfigurationProperty("MaxIdleTime", IsRequired = false)]
51 | public int MaxIdleTime
52 | {
53 | get { return (int) base["MaxIdleTime"]; }
54 | set { base["MaxIdleTime"] = value; }
55 | }
56 |
57 | [ConfigurationProperty("UserName", IsRequired = false)]
58 | public string UserName
59 | {
60 | get { return (string)base["UserName"]; }
61 | set { base["UserName"] = value; }
62 | }
63 |
64 | [ConfigurationProperty("Password", IsRequired = false)]
65 | public string Password
66 | {
67 | get { return (string)base["Password"]; }
68 | set { base["Password"] = value; }
69 | }
70 |
71 | [ConfigurationProperty("SafeCharsRegex", IsRequired = false)]
72 | public string SafeCharsRegex
73 | {
74 | get { return (string)base["SafeCharsRegex"]; }
75 | set { base["SafeCharsRegex"] = value; }
76 | }
77 |
78 | [ConfigurationProperty("ReplaceWith", IsRequired = false)]
79 | public string ReplaceWith
80 | {
81 | get { return (string)base["ReplaceWith"]; }
82 | set { base["ReplaceWith"] = value; }
83 | }
84 |
85 | [ConfigurationProperty("Proxy", IsRequired = true)]
86 | public ProxyConfig Proxy
87 | {
88 | get { return (ProxyConfig) base["Proxy"]; }
89 | set { base["Proxy"] = value; }
90 | }
91 |
92 | public sealed class ProxyConfig : ConfigurationElement
93 | {
94 | [ConfigurationProperty("Enable", IsRequired = true)]
95 | public bool Enable
96 | {
97 | get { return (bool) base["Enable"]; }
98 | set { base["Enable"] = value; }
99 | }
100 |
101 | [ConfigurationProperty("Url", IsRequired = true)]
102 | public string Url
103 | {
104 | get { return (string) base["Url"]; }
105 | set { base["Url"] = value; }
106 | }
107 | }
108 | }
109 |
110 | public sealed class WriteHttpNodeConfigCollection : ConfigurationElementCollection
111 | {
112 | protected override ConfigurationElement CreateNewElement()
113 | {
114 | return new WriteHttpNodeConfig();
115 | }
116 |
117 | protected override object GetElementKey(ConfigurationElement element)
118 | {
119 | var nodeConfig = (WriteHttpNodeConfig) element;
120 | return (nodeConfig.Name);
121 | }
122 | }
123 | }
124 | }
125 |
126 | // ----------------------------------------------------------------------------
127 | // Copyright (C) 2015 Bloomberg Finance L.P.
128 | //
129 | // Licensed under the Apache License, Version 2.0 (the "License");
130 | // you may not use this file except in compliance with the License.
131 | // You may obtain a copy of the License at
132 | // http://www.apache.org/licenses/LICENSE-2.0
133 | // Unless required by applicable law or agreed to in writing, software
134 | // distributed under the License is distributed on an "AS IS" BASIS,
135 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136 | // See the License for the specific language governing permissions and
137 | // limitations under the License.
138 | //
139 | // ----------------------------- END-OF-FILE ----------------------------------
140 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## [v0.5.19](https://github.com/bloomberg/collectdwin/tree/v0.5.19) (2017-09-29)
4 | [Full Changelog](https://github.com/bloomberg/collectdwin/compare/v0.5.14...v0.5.19)
5 |
6 | **Implemented enhancements:**
7 |
8 | - Add to Chocolatey [\#1](https://github.com/bloomberg/collectdwin/issues/1)
9 |
10 | **Closed issues:**
11 |
12 | - InvalidOperationException thrown when a performance category does not exist [\#35](https://github.com/bloomberg/collectdwin/issues/35)
13 | - Lot of System.FormatException in eventlog [\#33](https://github.com/bloomberg/collectdwin/issues/33)
14 |
15 | **Merged pull requests:**
16 |
17 | - Add a new configuration option : HostName. Use it in WindowsPerfo… [\#41](https://github.com/bloomberg/collectdwin/pull/41) ([tpoindessous](https://github.com/tpoindessous))
18 | - Fix broken headings in Markdown files [\#38](https://github.com/bloomberg/collectdwin/pull/38) ([bryant1410](https://github.com/bryant1410))
19 | - Catch exception due to invalid performance category and log error [\#36](https://github.com/bloomberg/collectdwin/pull/36) ([yogeswaran](https://github.com/yogeswaran))
20 | - fixed string format to match the number of arguments [\#34](https://github.com/bloomberg/collectdwin/pull/34) ([yogeswaran](https://github.com/yogeswaran))
21 |
22 | ## [v0.5.14](https://github.com/bloomberg/collectdwin/tree/v0.5.14) (2016-03-22)
23 | [Full Changelog](https://github.com/bloomberg/collectdwin/compare/v0.5.8...v0.5.14)
24 |
25 | **Fixed bugs:**
26 |
27 | - Install Fails on 2008, 2012 64 bit [\#2](https://github.com/bloomberg/collectdwin/issues/2)
28 |
29 | **Closed issues:**
30 |
31 | - Console Output [\#29](https://github.com/bloomberg/collectdwin/issues/29)
32 |
33 | **Merged pull requests:**
34 |
35 | - Add support for metadata and unit tests [\#28](https://github.com/bloomberg/collectdwin/pull/28) ([yogeswaran](https://github.com/yogeswaran))
36 | - fix a bug with AveragesGenerator and add more debug log info. [\#27](https://github.com/bloomberg/collectdwin/pull/27) ([budaqing](https://github.com/budaqing))
37 | - fix a bug with creating genrators [\#26](https://github.com/bloomberg/collectdwin/pull/26) ([budaqing](https://github.com/budaqing))
38 | - add more metrics for Windows [\#25](https://github.com/bloomberg/collectdwin/pull/25) ([budaqing](https://github.com/budaqing))
39 | - Only log error on sequential failures [\#24](https://github.com/bloomberg/collectdwin/pull/24) ([shanson7](https://github.com/shanson7))
40 | - Configurations changes to make metrics in synch with Unix Collectd [\#23](https://github.com/bloomberg/collectdwin/pull/23) ([yogeswaran](https://github.com/yogeswaran))
41 | - make collectdwin be able to both upgrade and downgrade. [\#22](https://github.com/bloomberg/collectdwin/pull/22) ([budaqing](https://github.com/budaqing))
42 |
43 | ## [v0.5.8](https://github.com/bloomberg/collectdwin/tree/v0.5.8) (2015-11-11)
44 | [Full Changelog](https://github.com/bloomberg/collectdwin/compare/v0.5.3...v0.5.8)
45 |
46 | **Closed issues:**
47 |
48 | - Hostname/Machinename [\#15](https://github.com/bloomberg/collectdwin/issues/15)
49 | - Monitoring Instance="\*" issues [\#12](https://github.com/bloomberg/collectdwin/issues/12)
50 | - Event timestamp in metric JSON can have comma as the decimal separator [\#10](https://github.com/bloomberg/collectdwin/issues/10)
51 |
52 | **Merged pull requests:**
53 |
54 | - Fix delay in publishing last batch [\#21](https://github.com/bloomberg/collectdwin/pull/21) ([yogeswaran](https://github.com/yogeswaran))
55 | - Adding basic auth to the WriteHttp plugin and minor functionality extentions [\#20](https://github.com/bloomberg/collectdwin/pull/20) ([FerventGeek](https://github.com/FerventGeek))
56 | - Added tool for versioning [\#19](https://github.com/bloomberg/collectdwin/pull/19) ([yogeswaran](https://github.com/yogeswaran))
57 | - Try to find FQDN of host [\#18](https://github.com/bloomberg/collectdwin/pull/18) ([pall-valmundsson](https://github.com/pall-valmundsson))
58 | - Add WindowsPerformanceCounter configuration reloads on intervals [\#17](https://github.com/bloomberg/collectdwin/pull/17) ([pall-valmundsson](https://github.com/pall-valmundsson))
59 | - Remove manifest properties to support msbuild on build machines [\#16](https://github.com/bloomberg/collectdwin/pull/16) ([yogeswaran](https://github.com/yogeswaran))
60 | - Handle missing instances [\#14](https://github.com/bloomberg/collectdwin/pull/14) ([pall-valmundsson](https://github.com/pall-valmundsson))
61 | - Fix JSON timestamp [\#13](https://github.com/bloomberg/collectdwin/pull/13) ([pall-valmundsson](https://github.com/pall-valmundsson))
62 | - Split app.config into per-plugin config file [\#11](https://github.com/bloomberg/collectdwin/pull/11) ([yogeswaran](https://github.com/yogeswaran))
63 |
64 | ## [v0.5.3](https://github.com/bloomberg/collectdwin/tree/v0.5.3) (2015-09-09)
65 | [Full Changelog](https://github.com/bloomberg/collectdwin/compare/v0.5.2...v0.5.3)
66 |
67 | **Implemented enhancements:**
68 |
69 | - Collectd http write plugin [\#5](https://github.com/bloomberg/collectdwin/issues/5)
70 |
71 | **Merged pull requests:**
72 |
73 | - Too many log archive files [\#9](https://github.com/bloomberg/collectdwin/pull/9) ([yogeswaran](https://github.com/yogeswaran))
74 | - Added support for WriteHttp plugin [\#8](https://github.com/bloomberg/collectdwin/pull/8) ([yogeswaran](https://github.com/yogeswaran))
75 | - Added support for running in console mode for troubleshooting [\#7](https://github.com/bloomberg/collectdwin/pull/7) ([yogeswaran](https://github.com/yogeswaran))
76 |
77 | ## [v0.5.2](https://github.com/bloomberg/collectdwin/tree/v0.5.2) (2015-06-22)
78 | [Full Changelog](https://github.com/bloomberg/collectdwin/compare/v0.5.1...v0.5.2)
79 |
80 | **Merged pull requests:**
81 |
82 | - Installer should not be starting the service [\#6](https://github.com/bloomberg/collectdwin/pull/6) ([yogeswaran](https://github.com/yogeswaran))
83 |
84 | ## [v0.5.1](https://github.com/bloomberg/collectdwin/tree/v0.5.1) (2015-06-08)
85 |
86 |
87 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
--------------------------------------------------------------------------------
/src/CollectdWinService/AmqpPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Configuration;
3 | using System.Text;
4 | using NLog;
5 | using RabbitMQ.Client;
6 |
7 | namespace BloombergFLP.CollectdWin
8 | {
9 | internal class AmqpPlugin : IMetricsWritePlugin
10 | {
11 | private const int ConnectionRetryDelay = 60; // 1 minute
12 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
13 | private readonly Object _connectionLock;
14 | private IModel _channel;
15 | private bool _connected;
16 | private IConnection _connection;
17 | private string _exchange;
18 | private double _lastConnectTime;
19 | private string _routingKeyPrefix;
20 | private string _url;
21 |
22 | public AmqpPlugin()
23 | {
24 | _connected = false;
25 | _lastConnectTime = 0;
26 | _connectionLock = new object();
27 | }
28 |
29 | public void Configure()
30 | {
31 | var config = ConfigurationManager.GetSection("Amqp") as AmqpPluginConfig;
32 | if (config == null)
33 | {
34 | throw new Exception("Cannot get configuration section : Amqp");
35 | }
36 |
37 | string user = config.Publish.User;
38 | string password = config.Publish.Password;
39 | string host = config.Publish.Host;
40 | int port = config.Publish.Port;
41 | string vhost = config.Publish.VirtualHost;
42 |
43 | _url = "amqp://" + user + ":" + password + "@" + host + ":" + port + "/" + vhost;
44 | _exchange = config.Publish.Exchange;
45 | _routingKeyPrefix = config.Publish.RoutingKeyPrefix;
46 | Logger.Info("Amqp plugin configured");
47 | }
48 |
49 | public void Start()
50 | {
51 | Logger.Trace("Start() begin.");
52 | StartConnection();
53 | Logger.Info("Amqp plugin started");
54 | }
55 |
56 | public void Stop()
57 | {
58 | Logger.Trace("CloseConnection() begin");
59 | CloseConnection();
60 | Logger.Info("Amqp plugin stopped");
61 | }
62 |
63 | public void Write(MetricValue metric)
64 | {
65 | if (metric == null)
66 | {
67 | Logger.Debug("write() - Invalid null metric");
68 | return;
69 | }
70 | if (!_connected)
71 | StartConnection();
72 | if (_connected && _channel != null)
73 | {
74 | string routingKey = GetAmqpRoutingKey(metric);
75 | string message = metric.GetMetricJsonStr();
76 | try
77 | {
78 | _channel.BasicPublish(_exchange, routingKey, null, Encoding.UTF8.GetBytes(message));
79 | }
80 | catch
81 | {
82 | CloseConnection();
83 | }
84 | }
85 | }
86 |
87 | public void Flush()
88 | {
89 | Logger.Trace("Amqp plugin flushing");
90 | }
91 |
92 | public void StartConnection()
93 | {
94 | double now = Util.GetNow();
95 | if (now < (_lastConnectTime + ConnectionRetryDelay))
96 | {
97 | return;
98 | }
99 | lock (_connectionLock)
100 | {
101 | try
102 | {
103 | var cf = new ConnectionFactory {Uri = _url};
104 | _connection = cf.CreateConnection();
105 | _channel = _connection.CreateModel();
106 |
107 | _connected = true;
108 | _lastConnectTime = Util.GetNow();
109 | Logger.Debug("Connection started.");
110 | }
111 | catch (Exception exp)
112 | {
113 | Logger.Error("Got exception when connecting to AMQP broker : ", exp);
114 | }
115 | }
116 | }
117 |
118 | public void CloseConnection()
119 | {
120 | lock (_connectionLock)
121 | {
122 | try
123 | {
124 | _channel.Close();
125 | _connection.Close();
126 | Logger.Debug("Connection closed.");
127 | }
128 | catch (Exception exp)
129 | {
130 | Logger.Error("Got exception when closing AMQP connection : ", exp);
131 | }
132 | _connected = false;
133 | }
134 | }
135 |
136 | private string GetAmqpRoutingKey(MetricValue metric)
137 | {
138 | string routingKey = _routingKeyPrefix + "." + metric.HostName + "." + metric.PluginName + "." +
139 | metric.PluginInstanceName + "." + metric.TypeName + "." + metric.TypeInstanceName;
140 |
141 | return (routingKey);
142 | }
143 | }
144 | }
145 |
146 | // ----------------------------------------------------------------------------
147 | // Copyright (C) 2015 Bloomberg Finance L.P.
148 | //
149 | // Licensed under the Apache License, Version 2.0 (the "License");
150 | // you may not use this file except in compliance with the License.
151 | // You may obtain a copy of the License at
152 | // http://www.apache.org/licenses/LICENSE-2.0
153 | // Unless required by applicable law or agreed to in writing, software
154 | // distributed under the License is distributed on an "AS IS" BASIS,
155 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
156 | // See the License for the specific language governing permissions and
157 | // limitations under the License.
158 | //
159 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/MetricsPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using NLog;
5 | using System.Web.Script.Serialization;
6 |
7 | namespace BloombergFLP.CollectdWin
8 | {
9 | internal interface IMetricsPlugin
10 | {
11 | void Configure();
12 | void Start();
13 | void Stop();
14 | }
15 |
16 | internal interface IMetricsReadPlugin : IMetricsPlugin
17 | {
18 | IList Read();
19 | }
20 |
21 | internal interface IMetricsWritePlugin : IMetricsPlugin
22 | {
23 | void Write(MetricValue metric);
24 | void Flush();
25 | }
26 |
27 | public class MetricValue
28 | {
29 | private const string MetricJsonFormat =
30 | @"{{""host"":""{0}"", ""plugin"":""{1}"", ""plugin_instance"":""{2}""," +
31 | @" ""type"":""{3}"", ""type_instance"":""{4}"", ""time"":{5}, ""interval"":{6}," +
32 | @" ""dstypes"":[{7}], ""dsnames"":[{8}], ""values"":[{9}]{10}}}";
33 | private const string MetaDataJsonFormat = @", ""meta"":{0}";
34 |
35 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
36 |
37 | private readonly IDictionary Meta = new SortedDictionary();
38 |
39 | public string HostName { get; set; }
40 | public string PluginName { get; set; }
41 | public string PluginInstanceName { get; set; }
42 | public string TypeName { get; set; }
43 | public string TypeInstanceName { get; set; }
44 |
45 | public int Interval { get; set; }
46 | public double Epoch { get; set; }
47 | public double[] Values { get; set; }
48 |
49 | public IDictionary MetaData
50 | {
51 | get
52 | {
53 | return Meta;
54 | }
55 | }
56 |
57 | public void AddMetaData(string tagName, string tagValue)
58 | {
59 | Meta[tagName] = tagValue;
60 | }
61 |
62 | public void AddMetaData(IDictionary meta)
63 | {
64 | if (meta == null)
65 | {
66 | return;
67 | }
68 | foreach(var tag in meta)
69 | {
70 | Meta[tag.Key] = tag.Value;
71 | }
72 | }
73 |
74 | public string Key()
75 | {
76 | return (HostName + "." + PluginName + "." + PluginInstanceName + "." + TypeName + "." + TypeInstanceName);
77 | }
78 |
79 | public MetricValue DeepCopy()
80 | {
81 | var other = (MetricValue) MemberwiseClone();
82 | other.HostName = String.Copy(HostName);
83 | other.PluginName = String.Copy(PluginName);
84 | other.PluginInstanceName = String.Copy(PluginInstanceName);
85 | other.TypeName = String.Copy(TypeName);
86 | other.TypeInstanceName = String.Copy(TypeInstanceName);
87 | other.Values = (double[]) Values.Clone();
88 | return (other);
89 | }
90 |
91 | public string EscapeString(string str)
92 | {
93 | if (string.IsNullOrEmpty(str))
94 | {
95 | return (str);
96 | }
97 | return (str.Replace(@"\", @"\\"));
98 | }
99 |
100 | public string GetMetaDataJsonStr()
101 | {
102 | return(new JavaScriptSerializer().Serialize(MetaData));
103 | }
104 |
105 | public string GetMetricJsonStr()
106 | {
107 | IList dsList = DataSetCollection.Instance.GetDataSource(TypeName);
108 | var dsNames = new List();
109 | var dsTypes = new List();
110 | if (dsList == null)
111 | {
112 | Logger.Debug("Invalid type : {0}, not found in types.db", TypeName);
113 | }
114 | else
115 | {
116 | foreach (DataSource ds in dsList)
117 | {
118 | dsNames.Add(ds.Name);
119 | dsTypes.Add(ds.Type.ToString().ToLower());
120 | }
121 | }
122 | String epochStr = Epoch.ToString(CultureInfo.InvariantCulture);
123 | string dsTypesStr = string.Join(",", dsTypes.ConvertAll(m => string.Format("\"{0}\"", m)).ToArray());
124 | string dsNamesStr = string.Join(",", dsNames.ConvertAll(m => string.Format("\"{0}\"", m)).ToArray());
125 | string valStr = string.Join(",", Array.ConvertAll(Values, val => val.ToString(CultureInfo.InvariantCulture)));
126 |
127 |
128 | var metaDataStr = "";
129 | if (MetaData.Count > 0)
130 | {
131 | metaDataStr = string.Format(MetaDataJsonFormat, GetMetaDataJsonStr());
132 | }
133 | var res = "";
134 | try
135 | {
136 | res = string.Format(MetricJsonFormat, HostName, PluginName,
137 | EscapeString(PluginInstanceName), TypeName, EscapeString(TypeInstanceName), epochStr,
138 | Interval, dsTypesStr, dsNamesStr, valStr, metaDataStr);
139 | }
140 | catch (Exception exp)
141 | {
142 | Logger.Error("Got exception in json conversion : {0}", exp);
143 | }
144 | return (res);
145 | }
146 | }
147 | }
148 |
149 | // ----------------------------------------------------------------------------
150 | // Copyright (C) 2015 Bloomberg Finance L.P.
151 | //
152 | // Licensed under the Apache License, Version 2.0 (the "License");
153 | // you may not use this file except in compliance with the License.
154 | // You may obtain a copy of the License at
155 | // http://www.apache.org/licenses/LICENSE-2.0
156 | // Unless required by applicable law or agreed to in writing, software
157 | // distributed under the License is distributed on an "AS IS" BASIS,
158 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
159 | // See the License for the specific language governing permissions and
160 | // limitations under the License.
161 | //
162 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/config/WindowsPerformanceCounterPluginConfig.cs:
--------------------------------------------------------------------------------
1 | using System.Configuration;
2 |
3 | namespace BloombergFLP.CollectdWin
4 | {
5 | internal class WindowsPerformanceCounterPluginConfig : ConfigurationSection
6 | {
7 | [ConfigurationProperty("RefreshInstancesConfiguration", IsRequired = true)]
8 | public RefreshInstancesConfigurationConfig RefreshInstancesConfiguration
9 | {
10 | get { return (RefreshInstancesConfigurationConfig)base["RefreshInstancesConfiguration"]; }
11 | set { base["RefreshInstancesConfiguration"] = value; }
12 | }
13 |
14 | public sealed class RefreshInstancesConfigurationConfig : ConfigurationElement
15 | {
16 | [ConfigurationProperty("Enable", IsRequired = true)]
17 | public bool Enable
18 | {
19 | get { return (bool)base["Enable"]; }
20 | set { base["Enable"] = value; }
21 | }
22 |
23 | [ConfigurationProperty("Interval", IsRequired = true)]
24 | public int Interval
25 | {
26 | get { return (int)base["Interval"]; }
27 | set { base["Interval"] = value; }
28 | }
29 | }
30 |
31 | [ConfigurationProperty("Counters", IsRequired = false)]
32 | [ConfigurationCollection(typeof (CounterConfigCollection), AddItemName = "Counter")]
33 | public CounterConfigCollection Counters
34 | {
35 | get { return (CounterConfigCollection) base["Counters"]; }
36 | set { base["Counters"] = value; }
37 | }
38 |
39 | public static WindowsPerformanceCounterPluginConfig GetConfig()
40 | {
41 | return
42 | (WindowsPerformanceCounterPluginConfig)
43 | ConfigurationManager.GetSection("WindowsPerformanceCounterPlugin") ??
44 | new WindowsPerformanceCounterPluginConfig();
45 | }
46 |
47 | public sealed class CounterConfig : ConfigurationElement
48 | {
49 | [ConfigurationProperty("Transformer", IsRequired = false, DefaultValue = "")]
50 | public string Transformer
51 | {
52 | get { return (string)base["Transformer"]; }
53 | set { base["Transformer"] = value; }
54 | }
55 |
56 | [ConfigurationProperty("TransformerParameters", IsRequired = false)]
57 | public string TransformerParameters
58 | {
59 | get { return (string)base["TransformerParameters"]; }
60 | set { base["TransformerParameters"] = value; }
61 | }
62 |
63 | [ConfigurationProperty("Category", IsRequired = true)]
64 | public string Category
65 | {
66 | get { return (string) base["Category"]; }
67 | set { base["Category"] = value; }
68 | }
69 |
70 | [ConfigurationProperty("Name", IsRequired = true)]
71 | public string Name
72 | {
73 | get { return (string) base["Name"]; }
74 | set { base["Name"] = value; }
75 | }
76 |
77 |
78 | [ConfigurationProperty("Instance", IsRequired = false)]
79 | public string Instance
80 | {
81 | get { return (string) base["Instance"]; }
82 | set { base["Instance"] = value; }
83 | }
84 |
85 | [ConfigurationProperty("CollectdPlugin", IsRequired = true)]
86 | public string CollectdPlugin
87 | {
88 | get { return (string) base["CollectdPlugin"]; }
89 | set { base["CollectdPlugin"] = value; }
90 | }
91 |
92 | [ConfigurationProperty("CollectdPluginInstance", IsRequired = false)]
93 | public string CollectdPluginInstance
94 | {
95 | get { return (string) base["CollectdPluginInstance"]; }
96 | set { base["CollectdPluginInstance"] = value; }
97 | }
98 |
99 | [ConfigurationProperty("CollectdType", IsRequired = true)]
100 | public string CollectdType
101 | {
102 | get { return (string) base["CollectdType"]; }
103 | set { base["CollectdType"] = value; }
104 | }
105 |
106 | [ConfigurationProperty("CollectdTypeInstance", IsRequired = true)]
107 | public string CollectdTypeInstance
108 | {
109 | get { return (string) base["CollectdTypeInstance"]; }
110 | set { base["CollectdTypeInstance"] = value; }
111 | }
112 | }
113 |
114 | public sealed class CounterConfigCollection : ConfigurationElementCollection
115 | {
116 | protected override ConfigurationElement CreateNewElement()
117 | {
118 | return new CounterConfig();
119 | }
120 |
121 | protected override object GetElementKey(ConfigurationElement element)
122 | {
123 | var counterConfig = (CounterConfig) element;
124 | return (counterConfig.CollectdPlugin + "_" + counterConfig.CollectdPluginInstance + "_" + counterConfig.CollectdType + "_" + counterConfig.CollectdTypeInstance);
125 | }
126 | }
127 | }
128 | }
129 |
130 | // ----------------------------------------------------------------------------
131 | // Copyright (C) 2015 Bloomberg Finance L.P.
132 | //
133 | // Licensed under the Apache License, Version 2.0 (the "License");
134 | // you may not use this file except in compliance with the License.
135 | // You may obtain a copy of the License at
136 | // http://www.apache.org/licenses/LICENSE-2.0
137 | // Unless required by applicable law or agreed to in writing, software
138 | // distributed under the License is distributed on an "AS IS" BASIS,
139 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
140 | // See the License for the specific language governing permissions and
141 | // limitations under the License.
142 | //
143 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/CollectdWinService.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | False
122 |
123 |
--------------------------------------------------------------------------------
/src/CollectdWinService/config/StatsdPluginConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Configuration;
3 |
4 | namespace BloombergFLP.CollectdWin
5 | {
6 | internal class StatsdPluginConfig : ConfigurationSection
7 | {
8 | [ConfigurationProperty("Server", IsRequired = true)]
9 | public ServerConfig Server
10 | {
11 | get { return (ServerConfig) base["Server"]; }
12 | set { base["Server"] = value; }
13 | }
14 |
15 | [ConfigurationProperty("DeleteCache", IsRequired = true)]
16 | public DeleteCacheConfig DeleteCache
17 | {
18 | get { return (DeleteCacheConfig) base["DeleteCache"]; }
19 | set { base["DeleteCache"] = value; }
20 | }
21 |
22 | [ConfigurationProperty("Timer", IsRequired = true)]
23 | public TimerConfig Timer
24 | {
25 | get { return (TimerConfig) base["Timer"]; }
26 | set { base["Timer"] = value; }
27 | }
28 |
29 | public static StatsdPluginConfig GetConfig()
30 | {
31 | return (StatsdPluginConfig) ConfigurationManager.GetSection("Statsd") ?? new StatsdPluginConfig();
32 | }
33 |
34 | public sealed class DeleteCacheConfig : ConfigurationElement
35 | {
36 | [ConfigurationProperty("Counters", IsRequired = true)]
37 | public bool Counters
38 | {
39 | get { return (bool) base["Counters"]; }
40 | set { base["Counters"] = value; }
41 | }
42 |
43 | [ConfigurationProperty("Timers", IsRequired = true)]
44 | public bool Timers
45 | {
46 | get { return (bool) base["Timers"]; }
47 | set { base["Timers"] = value; }
48 | }
49 |
50 | [ConfigurationProperty("Gauges", IsRequired = true)]
51 | public bool Gauges
52 | {
53 | get { return (bool) base["Gauges"]; }
54 | set { base["Gauges"] = value; }
55 | }
56 |
57 | [ConfigurationProperty("Sets", IsRequired = true)]
58 | public bool Sets
59 | {
60 | get { return (bool) base["Sets"]; }
61 | set { base["Sets"] = value; }
62 | }
63 | }
64 |
65 | public class PercentileCollection : ConfigurationElementCollection
66 | {
67 | protected override ConfigurationElement CreateNewElement()
68 | {
69 | return new PercentileConfig();
70 | }
71 |
72 | protected override object GetElementKey(ConfigurationElement element)
73 | {
74 | return (((PercentileConfig) element).UniqueId);
75 | }
76 | }
77 |
78 | public sealed class PercentileConfig : ConfigurationElement
79 | {
80 | public PercentileConfig()
81 | {
82 | UniqueId = Guid.NewGuid();
83 | }
84 |
85 | internal Guid UniqueId { get; set; }
86 |
87 | [ConfigurationProperty("Value", IsRequired = true)]
88 | public float Value
89 | {
90 | get { return (float) base["Value"]; }
91 | set { base["Value"] = value; }
92 | }
93 | }
94 |
95 | public sealed class ServerConfig : ConfigurationElement
96 | {
97 | [ConfigurationProperty("Host", IsRequired = true)]
98 | public string Host
99 | {
100 | get { return (string) base["Host"]; }
101 | set { base["Host"] = value; }
102 | }
103 |
104 | [ConfigurationProperty("Port", IsRequired = true)]
105 | public int Port
106 | {
107 | get { return (int) base["Port"]; }
108 | set { base["Port"] = value; }
109 | }
110 | }
111 |
112 | public sealed class TimerConfig : ConfigurationElement
113 | {
114 | [ConfigurationProperty("Lower", IsRequired = true)]
115 | public bool Lower
116 | {
117 | get { return (bool) base["Lower"]; }
118 | set { base["Lower"] = value; }
119 | }
120 |
121 | [ConfigurationProperty("Upper", IsRequired = true)]
122 | public bool Upper
123 | {
124 | get { return (bool) base["Upper"]; }
125 | set { base["Upper"] = value; }
126 | }
127 |
128 | [ConfigurationProperty("Sum", IsRequired = true)]
129 | public bool Sum
130 | {
131 | get { return (bool) base["Sum"]; }
132 | set { base["Sum"] = value; }
133 | }
134 |
135 | [ConfigurationProperty("Count", IsRequired = true)]
136 | public bool Count
137 | {
138 | get { return (bool) base["Count"]; }
139 | set { base["Count"] = value; }
140 | }
141 |
142 | [ConfigurationProperty("Percentiles", IsRequired = false)]
143 | [ConfigurationCollection(typeof (PercentileCollection), AddItemName = "Percentile")]
144 | public PercentileCollection Percentiles
145 | {
146 | get { return (PercentileCollection) base["Percentiles"]; }
147 | set { base["Percentiles"] = value; }
148 | }
149 | }
150 | }
151 | }
152 |
153 | // ----------------------------------------------------------------------------
154 | // Copyright (C) 2015 Bloomberg Finance L.P.
155 | //
156 | // Licensed under the Apache License, Version 2.0 (the "License");
157 | // you may not use this file except in compliance with the License.
158 | // You may obtain a copy of the License at
159 | // http://www.apache.org/licenses/LICENSE-2.0
160 | // Unless required by applicable law or agreed to in writing, software
161 | // distributed under the License is distributed on an "AS IS" BASIS,
162 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
163 | // See the License for the specific language governing permissions and
164 | // limitations under the License.
165 | //
166 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/installer/Product.wxs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
24 |
28 |
31 |
34 |
36 |
37 |
38 |
40 |
42 |
48 |
54 |
60 |
66 |
72 |
82 |
87 |
88 |
89 |
90 |
96 |
102 |
108 |
114 |
120 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/src/CollectdWinService/config/CollectdWinConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 |
5 | namespace BloombergFLP.CollectdWin
6 | {
7 |
8 | internal class CollectdWinConfigHelper
9 | {
10 | public static IDictionary getMetaData()
11 | {
12 | IDictionary metaData = new Dictionary();
13 |
14 | var coreConfig = ConfigurationManager.GetSection("CollectdWinConfig") as CollectdWinConfig;
15 | if (coreConfig == null)
16 | {
17 | throw new Exception("Cannot get configuration section : CollectdWinConfig");
18 | }
19 | foreach (CollectdWinConfig.TagConfig tagConfig in coreConfig.MetaData)
20 | {
21 | metaData[tagConfig.Name] = tagConfig.Value;
22 | }
23 | return (metaData);
24 | }
25 | }
26 |
27 | internal class CollectdWinConfig : ConfigurationSection
28 | {
29 | [ConfigurationProperty("GeneralSettings", IsRequired = true)]
30 | public GeneralSettingsConfig GeneralSettings
31 | {
32 | get { return (GeneralSettingsConfig) base["GeneralSettings"]; }
33 | set { base["GeneralSettings"] = value; }
34 | }
35 |
36 | [ConfigurationProperty("Plugins", IsRequired = true)]
37 | [ConfigurationCollection(typeof (PluginCollection), AddItemName = "Plugin")]
38 | public PluginCollection Plugins
39 | {
40 | get { return (PluginCollection) base["Plugins"]; }
41 | set { base["Plugins"] = value; }
42 | }
43 |
44 | [ConfigurationProperty("MetaData", IsRequired = false)]
45 | [ConfigurationCollection(typeof(TagCollection), AddItemName = "Tag")]
46 | public TagCollection MetaData
47 | {
48 | get { return (TagCollection)base["MetaData"]; }
49 | set { base["MetaData"] = value; }
50 | }
51 |
52 | public static CollectdWinConfig GetConfig()
53 | {
54 | return (CollectdWinConfig) ConfigurationManager.GetSection("CollectdWinConfig") ?? new CollectdWinConfig();
55 | }
56 |
57 | public sealed class GeneralSettingsConfig : ConfigurationElement
58 | {
59 | [ConfigurationProperty("Interval", IsRequired = true)]
60 | public int Interval
61 | {
62 | get { return (int) base["Interval"]; }
63 | set { base["Interval"] = value; }
64 | }
65 |
66 | [ConfigurationProperty("Timeout", IsRequired = true)]
67 | public int Timeout
68 | {
69 | get { return (int) base["Timeout"]; }
70 | set { base["Timeout"] = value; }
71 | }
72 |
73 | [ConfigurationProperty("StoreRates", IsRequired = true)]
74 | public bool StoreRates
75 | {
76 | get { return (bool) base["StoreRates"]; }
77 | set { base["StoreRates"] = value; }
78 | }
79 |
80 | [ConfigurationProperty("HostName", IsRequired = false)]
81 | public string HostName
82 | {
83 | get { return (string) base["HostName"]; }
84 | set { base["HostName"] = value; }
85 | }
86 | }
87 |
88 | public sealed class PluginCollection : ConfigurationElementCollection
89 | {
90 | protected override ConfigurationElement CreateNewElement()
91 | {
92 | return new PluginConfig();
93 | }
94 |
95 | protected override object GetElementKey(ConfigurationElement element)
96 | {
97 | return (((PluginConfig) element).UniqueId);
98 | }
99 | }
100 |
101 | public sealed class PluginConfig : ConfigurationElement
102 | {
103 | public PluginConfig()
104 | {
105 | UniqueId = Guid.NewGuid();
106 | }
107 |
108 | internal Guid UniqueId { get; set; }
109 |
110 | [ConfigurationProperty("Name", IsRequired = true)]
111 | public string Name
112 | {
113 | get { return (string) base["Name"]; }
114 | set { base["Name"] = value; }
115 | }
116 |
117 | [ConfigurationProperty("Class", IsRequired = true)]
118 | public string Class
119 | {
120 | get { return (string) base["Class"]; }
121 | set { base["Class"] = value; }
122 | }
123 |
124 | [ConfigurationProperty("Enable", IsRequired = true)]
125 | public bool Enable
126 | {
127 | get { return (bool) base["Enable"]; }
128 | set { base["Enable"] = value; }
129 | }
130 | }
131 |
132 | public sealed class TagCollection : ConfigurationElementCollection
133 | {
134 | protected override ConfigurationElement CreateNewElement()
135 | {
136 | return new TagConfig();
137 | }
138 |
139 | protected override object GetElementKey(ConfigurationElement element)
140 | {
141 | return (((TagConfig)element).UniqueId);
142 | }
143 | }
144 | public sealed class TagConfig : ConfigurationElement
145 | {
146 | public TagConfig()
147 | {
148 | UniqueId = Guid.NewGuid();
149 | }
150 |
151 | internal Guid UniqueId { get; set; }
152 |
153 | [ConfigurationProperty("Name", IsRequired = true)]
154 | public string Name
155 | {
156 | get { return (string)base["Name"]; }
157 | set { base["Name"] = value; }
158 | }
159 |
160 | [ConfigurationProperty("Value", IsRequired = true)]
161 | public string Value
162 | {
163 | get { return (string)base["Value"]; }
164 | set { base["Value"] = value; }
165 | }
166 | }
167 | }
168 | }
169 |
170 | // ----------------------------------------------------------------------------
171 | // Copyright (C) 2015 Bloomberg Finance L.P.
172 | //
173 | // Licensed under the Apache License, Version 2.0 (the "License");
174 | // you may not use this file except in compliance with the License.
175 | // You may obtain a copy of the License at
176 | // http://www.apache.org/licenses/LICENSE-2.0
177 | // Unless required by applicable law or agreed to in writing, software
178 | // distributed under the License is distributed on an "AS IS" BASIS,
179 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
180 | // See the License for the specific language governing permissions and
181 | // limitations under the License.
182 | //
183 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/TypesDB.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 | using System.Text.RegularExpressions;
6 | using NLog;
7 |
8 | namespace BloombergFLP.CollectdWin
9 | {
10 | public enum DsType
11 | {
12 | Absolute,
13 | Counter,
14 | Derive,
15 | Gauge
16 | };
17 |
18 | public enum Status
19 | {
20 | Success,
21 | Failure
22 | };
23 |
24 | public class DataSource
25 | {
26 | public DataSource(string name, DsType type, double min, double max)
27 | {
28 | Name = name;
29 | Type = type;
30 | Min = min;
31 | Max = max;
32 | }
33 |
34 | public string Name { get; set; }
35 | public DsType Type { get; set; }
36 | public double Min { get; set; }
37 | public double Max { get; set; }
38 | }
39 |
40 | internal class DataSetCollection
41 | {
42 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
43 | private static volatile DataSetCollection _instance;
44 | private static readonly object SyncRoot = new Object();
45 |
46 | private readonly Dictionary> _dataSetMap;
47 | //
48 |
49 | private DataSetCollection()
50 | {
51 | _dataSetMap = new Dictionary>();
52 | }
53 |
54 | public static DataSetCollection Instance
55 | {
56 | get
57 | {
58 | if (_instance == null)
59 | {
60 | lock (SyncRoot)
61 | {
62 | if (_instance == null)
63 | {
64 | _instance = new DataSetCollection();
65 | _instance.Load();
66 | }
67 | }
68 | }
69 | return _instance;
70 | }
71 | }
72 |
73 | private static Status GetDouble(string dstr, out double val)
74 | {
75 | if (dstr == "u" || dstr == "U")
76 | {
77 | val = Double.NaN;
78 | return (Status.Success);
79 | }
80 | try
81 | {
82 | val = Double.Parse(dstr);
83 | }
84 | catch (Exception)
85 | {
86 | val = Double.NaN;
87 | return (Status.Failure);
88 | }
89 | return (Status.Success);
90 | }
91 |
92 | public void Print()
93 | {
94 | var sb = new StringBuilder();
95 | foreach (var entry in _dataSetMap)
96 | {
97 | sb.Append(string.Format("\n[{0}] ==>", entry.Key));
98 | foreach (DataSource ds in entry.Value)
99 | {
100 | sb.Append(string.Format(" [{0}:{1}:{2}:{3}]", ds.Name, ds.Type, ds.Min, ds.Max));
101 | }
102 | }
103 | Console.WriteLine(sb.ToString());
104 | }
105 |
106 | public void Load()
107 | {
108 | const string dataSetPattern = @"[\s\t]*(\w+)[\s\t]*(.*)$";
109 | const string dataSourcePattern = @"(\w+):(ABSOLUTE|COUNTER|DERIVE|GAUGE):([+-]?\w+):([+-]?\w+)[,]?\s*";
110 |
111 | var dataSetRegex = new Regex(dataSetPattern, RegexOptions.IgnoreCase);
112 | var dataSourceRegex = new Regex(dataSourcePattern, RegexOptions.IgnoreCase);
113 |
114 | string fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "types.db");
115 | string[] lines = File.ReadAllLines(fileName);
116 |
117 | foreach (string line in lines)
118 | {
119 | // skip comments and blank lines
120 | if (line.StartsWith("#") || line.Trim() == string.Empty)
121 | {
122 | continue;
123 | }
124 | Match match = dataSetRegex.Match(line);
125 | if (match.Groups.Count < 3)
126 | {
127 | Logger.Error("types.db: invalid data set [{0}]", line);
128 | continue;
129 | }
130 | string dataSetName = match.Groups[1].Value;
131 | MatchCollection matches = dataSourceRegex.Matches(line);
132 | if (matches.Count < 1)
133 | {
134 | Logger.Error("types.db: invalid data source [{0}]", line);
135 | continue;
136 | }
137 | var dataSourceList = new List();
138 | foreach (Match m in matches)
139 | {
140 | if (m.Groups.Count != 5)
141 | {
142 | Logger.Error("types.db: cannot parse data source [{0}]", line);
143 | dataSourceList.Clear();
144 | break;
145 | }
146 |
147 | string dsName = m.Groups[1].Value;
148 | var dstype = (DsType) Enum.Parse(typeof (DsType), m.Groups[2].Value, true);
149 |
150 | double min, max;
151 |
152 | if (GetDouble(m.Groups[3].Value, out min) != Status.Success)
153 | {
154 | Logger.Error("types.db: invalid Min value [{0}]", line);
155 | dataSourceList.Clear();
156 | break;
157 | }
158 |
159 | if (GetDouble(m.Groups[4].Value, out max) != Status.Success)
160 | {
161 | Logger.Error("types.db: invalid Max value [{0}]", line);
162 | dataSourceList.Clear();
163 | break;
164 | }
165 |
166 | var ds = new DataSource(dsName, dstype, min, max);
167 | dataSourceList.Add(ds);
168 | }
169 | if (dataSourceList.Count > 0)
170 | {
171 | _dataSetMap[dataSetName] = dataSourceList;
172 | }
173 | }
174 | }
175 |
176 | public IList GetDataSource(string dataSetName)
177 | {
178 | IList dataSourceList;
179 | return (_dataSetMap.TryGetValue(dataSetName, out dataSourceList) ? (dataSourceList) : (null));
180 | }
181 | }
182 | }
183 |
184 | // ----------------------------------------------------------------------------
185 | // Copyright (C) 2015 Bloomberg Finance L.P.
186 | //
187 | // Licensed under the Apache License, Version 2.0 (the "License");
188 | // you may not use this file except in compliance with the License.
189 | // You may obtain a copy of the License at
190 | // http://www.apache.org/licenses/LICENSE-2.0
191 | // Unless required by applicable law or agreed to in writing, software
192 | // distributed under the License is distributed on an "AS IS" BASIS,
193 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
194 | // See the License for the specific language governing permissions and
195 | // limitations under the License.
196 | //
197 | // ----------------------------- END-OF-FILE ----------------------------------
198 |
--------------------------------------------------------------------------------
/src/CollectdWinService/Aggregator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using NLog;
5 |
6 | namespace BloombergFLP.CollectdWin
7 | {
8 | internal class CacheEntry
9 | {
10 | public MetricValue MetricRate;
11 | public double[] RawValues;
12 |
13 | public CacheEntry(MetricValue metricValue)
14 | {
15 | MetricRate = metricValue;
16 | RawValues = (double[]) metricValue.Values.Clone();
17 | }
18 | }
19 |
20 | internal class Aggregator
21 | {
22 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
23 | private readonly Dictionary _cache;
24 | private readonly Object _cacheLock;
25 | private readonly bool _storeRates;
26 | private readonly int _timeoutSeconds;
27 |
28 | public Aggregator(int timeoutSeconds, bool storeRates)
29 | {
30 | _cache = new Dictionary();
31 | _cacheLock = new Object();
32 | _timeoutSeconds = timeoutSeconds;
33 | _storeRates = storeRates;
34 | }
35 |
36 | public void Aggregate(ref MetricValue metricValue)
37 | {
38 | // If rates are not stored then there is nothing to aggregate
39 | if (!_storeRates)
40 | {
41 | return;
42 | }
43 | IList dsl = DataSetCollection.Instance.GetDataSource(metricValue.TypeName);
44 | if (dsl == null || metricValue.Values.Length != dsl.Count)
45 | {
46 | return;
47 | }
48 |
49 | double now = Util.GetNow();
50 |
51 | lock (_cacheLock)
52 | {
53 | CacheEntry cEntry;
54 | string key = metricValue.Key();
55 |
56 | if (!(_cache.TryGetValue(key, out cEntry)))
57 | {
58 | cEntry = new CacheEntry(metricValue.DeepCopy());
59 | for (int i = 0; i < metricValue.Values.Length; i++)
60 | {
61 | if (dsl[i].Type == DsType.Derive ||
62 | dsl[i].Type == DsType.Absolute ||
63 | dsl[i].Type == DsType.Counter)
64 | {
65 | metricValue.Values[i] = double.NaN;
66 | cEntry.MetricRate.Values[i] = double.NaN;
67 | }
68 | }
69 | cEntry.MetricRate.Epoch = now;
70 | _cache[key] = cEntry;
71 | return;
72 | }
73 | for (int i = 0; i < metricValue.Values.Length; i++)
74 | {
75 | double rawValNew = metricValue.Values[i];
76 | double rawValOld = cEntry.RawValues[i];
77 | double rawValDiff = rawValNew - rawValOld;
78 | double timeDiff = cEntry.MetricRate.Epoch - now;
79 |
80 | double rateNew = rawValDiff/timeDiff;
81 |
82 | switch (dsl[i].Type)
83 | {
84 | case DsType.Gauge:
85 | // no rates calculations are done, values are stored as-is for gauge
86 | cEntry.RawValues[i] = rawValNew;
87 | cEntry.MetricRate.Values[i] = rawValNew;
88 | break;
89 |
90 | case DsType.Absolute:
91 | // similar to gauge, except value will be divided by time diff
92 | cEntry.MetricRate.Values[i] = metricValue.Values[i]/timeDiff;
93 | cEntry.RawValues[i] = rawValNew;
94 | metricValue.Values[i] = cEntry.MetricRate.Values[i];
95 | break;
96 |
97 | case DsType.Derive:
98 | cEntry.RawValues[i] = rawValNew;
99 | cEntry.MetricRate.Values[i] = rateNew;
100 | metricValue.Values[i] = rateNew;
101 |
102 | break;
103 |
104 | case DsType.Counter:
105 | // Counters are very simlar to derive except when counter wraps around
106 | if (rawValNew < rawValOld)
107 | {
108 | // counter has wrapped around
109 | cEntry.MetricRate.Values[i] = metricValue.Values[i]/timeDiff;
110 | cEntry.RawValues[i] = rawValNew;
111 | metricValue.Values[i] = cEntry.MetricRate.Values[i];
112 | }
113 | else
114 | {
115 | cEntry.MetricRate.Values[i] = rateNew;
116 | cEntry.RawValues[i] = rawValNew;
117 | metricValue.Values[i] = rateNew;
118 | }
119 | break;
120 | }
121 |
122 | // range checks
123 | if (metricValue.Values[i] < dsl[i].Min)
124 | {
125 | metricValue.Values[i] = dsl[i].Min;
126 | cEntry.RawValues[i] = metricValue.Values[i];
127 | }
128 | if (metricValue.Values[i] > dsl[i].Max)
129 | {
130 | metricValue.Values[i] = dsl[i].Max;
131 | cEntry.RawValues[i] = metricValue.Values[i];
132 | }
133 |
134 | cEntry.MetricRate.Epoch = now;
135 | _cache[key] = cEntry;
136 | }
137 | }
138 | }
139 |
140 | public void RemoveExpiredEntries()
141 | {
142 | // If rates are not stored then there is nothing to remove
143 | if (!_storeRates)
144 | {
145 | return;
146 | }
147 | double now = Util.GetNow();
148 | double expirationTime = now - _timeoutSeconds;
149 | var removeList = new List();
150 |
151 | lock (_cacheLock)
152 | {
153 | removeList.AddRange(from pair in _cache
154 | let cEntry = pair.Value
155 | where cEntry.MetricRate.Epoch < expirationTime
156 | select pair.Key);
157 | if (removeList.Count > 0)
158 | Logger.Debug("Removing expired entries: {0}", removeList.Count);
159 | foreach (string key in removeList)
160 | {
161 | _cache.Remove(key);
162 | }
163 | }
164 | }
165 | }
166 | }
167 |
168 | // ----------------------------------------------------------------------------
169 | // Copyright (C) 2015 Bloomberg Finance L.P.
170 | //
171 | // Licensed under the Apache License, Version 2.0 (the "License");
172 | // you may not use this file except in compliance with the License.
173 | // You may obtain a copy of the License at
174 | // http://www.apache.org/licenses/LICENSE-2.0
175 | // Unless required by applicable law or agreed to in writing, software
176 | // distributed under the License is distributed on an "AS IS" BASIS,
177 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
178 | // See the License for the specific language governing permissions and
179 | // limitations under the License.
180 | //
181 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/StatsdAggregator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NLog;
4 |
5 | namespace BloombergFLP.CollectdWin
6 | {
7 | internal class StatsdAggregator
8 | {
9 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
10 |
11 | private readonly bool _delCounter;
12 | private readonly bool _delGauge;
13 | private readonly bool _delSet;
14 | private readonly bool _delTimer;
15 | private readonly string _hostName;
16 | private readonly Object _lock;
17 | private readonly Dictionary _metrics;
18 | private readonly float[] _percentiles;
19 | private readonly bool _timerCount;
20 | private readonly bool _timerLower;
21 | private readonly bool _timerSum;
22 | private readonly bool _timerUpper;
23 |
24 | public StatsdAggregator(bool delCounter, bool delTimer, bool delGauge, bool delSet, bool timerLower,
25 | bool timerUpper, bool timerSum, bool timerCount, float[] percentiles)
26 | {
27 | _lock = new Object();
28 | _metrics = new Dictionary();
29 | _hostName = Util.GetHostName();
30 |
31 | _delCounter = delCounter;
32 | _delTimer = delTimer;
33 | _delGauge = delGauge;
34 | _delSet = delSet;
35 |
36 | _timerLower = timerLower;
37 | _timerUpper = timerUpper;
38 | _timerSum = timerSum;
39 | _timerCount = timerCount;
40 |
41 | _percentiles = percentiles;
42 |
43 | if (_percentiles != null && _percentiles.Length > 0)
44 | StatsdMetric.Latency.HistogramEnabled = true;
45 | else
46 | StatsdMetric.Latency.HistogramEnabled = false;
47 |
48 | Logger.Info(
49 | "Statsd config - delCounter:{0}, delTimer:{1}, delGauge:{2}, delSet:{3}, isHistogramEnabled:{4}",
50 | _delCounter, _delTimer, _delGauge, _delSet, StatsdMetric.Latency.HistogramEnabled);
51 | }
52 |
53 | public void AddMetric(StatsdMetric metric)
54 | {
55 | string key = metric.Type + "_" + metric.Name;
56 | lock (_lock)
57 | {
58 | StatsdMetric oldMetric;
59 | if (_metrics.TryGetValue(key, out oldMetric))
60 | {
61 | //merge
62 | double val = metric.Value;
63 | oldMetric.AddValue(val);
64 | }
65 | else
66 | {
67 | _metrics[key] = metric;
68 | }
69 | }
70 | }
71 |
72 | public IList Read()
73 | {
74 | lock (_lock)
75 | {
76 | var res = new List();
77 | var removeList = new List();
78 | foreach (var pair in _metrics)
79 | {
80 | StatsdMetric metric = pair.Value;
81 | if (metric.NumUpdates <= 0 &&
82 | ((_delCounter && metric.Type == StatsdMetric.StatsdType.StatsdCounter) ||
83 | (_delTimer && metric.Type == StatsdMetric.StatsdType.StatsdTimer) ||
84 | (_delGauge && metric.Type == StatsdMetric.StatsdType.StatsdGauge) ||
85 | (_delSet && metric.Type == StatsdMetric.StatsdType.StatsdSet)))
86 | {
87 | removeList.Add(pair.Key);
88 | continue;
89 | }
90 | var metricVal = new MetricValue
91 | {
92 | HostName = _hostName,
93 | PluginName = "statsd",
94 | PluginInstanceName = "",
95 | TypeInstanceName = metric.Name,
96 | Values = new[] {metric.GetMetric()}
97 | };
98 | switch (metric.Type)
99 | {
100 | case StatsdMetric.StatsdType.StatsdGauge:
101 | metricVal.TypeName = "gauge";
102 | break;
103 | case StatsdMetric.StatsdType.StatsdTimer:
104 | metricVal.TypeName = "latency";
105 | metricVal.TypeInstanceName += "-average";
106 | break;
107 | case StatsdMetric.StatsdType.StatsdSet:
108 | metricVal.TypeName = "objects";
109 | break;
110 | default:
111 | metricVal.TypeName = "derive";
112 | break;
113 | }
114 | TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
115 | double epoch = t.TotalMilliseconds/1000;
116 | metricVal.Epoch = Math.Round(epoch, 3);
117 |
118 | res.Add(metricVal);
119 |
120 | if (metric.Type == StatsdMetric.StatsdType.StatsdTimer)
121 | {
122 | if (_timerLower)
123 | {
124 | MetricValue lowerValue = metricVal.DeepCopy();
125 | lowerValue.TypeInstanceName = metric.Name + "-lower";
126 | lowerValue.Values[0] = metric.Lat.Min;
127 | res.Add(lowerValue);
128 | }
129 | if (_timerUpper)
130 | {
131 | MetricValue upperValue = metricVal.DeepCopy();
132 | upperValue.TypeInstanceName = metric.Name + "-upper";
133 | upperValue.Values[0] = metric.Lat.Max;
134 | res.Add(upperValue);
135 | }
136 |
137 | if (_timerSum)
138 | {
139 | MetricValue upperSum = metricVal.DeepCopy();
140 | upperSum.TypeInstanceName = metric.Name + "-Sum";
141 | upperSum.Values[0] = metric.Lat.Sum;
142 | res.Add(upperSum);
143 | }
144 | if (_timerCount)
145 | {
146 | MetricValue upperCount = metricVal.DeepCopy();
147 | upperCount.TypeInstanceName = metric.Name + "-count";
148 | upperCount.Values[0] = metric.Lat.Num;
149 | res.Add(upperCount);
150 | }
151 | Histogram histogram = metric.Lat.Histogram;
152 | if (_percentiles != null && _percentiles.Length > 0 && histogram != null)
153 | {
154 | foreach (float percentile in _percentiles)
155 | {
156 | double val = histogram.GetPercentile(percentile);
157 |
158 | MetricValue mv = metricVal.DeepCopy();
159 | mv.TypeInstanceName = metric.Name + "-percentile-" + percentile;
160 | mv.Values[0] = val;
161 | res.Add(mv);
162 | }
163 | }
164 | }
165 | metric.Reset();
166 | }
167 | Logger.Debug("Removing entries that were not updated:{0}", removeList.Count);
168 | foreach (string key in removeList)
169 | {
170 | _metrics.Remove(key);
171 | }
172 | return (res);
173 | }
174 | }
175 | }
176 | }
177 |
178 | // ----------------------------------------------------------------------------
179 | // Copyright (C) 2015 Bloomberg Finance L.P.
180 | //
181 | // Licensed under the Apache License, Version 2.0 (the "License");
182 | // you may not use this file except in compliance with the License.
183 | // You may obtain a copy of the License at
184 | // http://www.apache.org/licenses/LICENSE-2.0
185 | // Unless required by applicable law or agreed to in writing, software
186 | // distributed under the License is distributed on an "AS IS" BASIS,
187 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
188 | // See the License for the specific language governing permissions and
189 | // limitations under the License.
190 | //
191 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/CollectdWinService.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D4244E6B-84EC-41A0-96A7-4F489F6098BC}
8 | Exe
9 | Properties
10 | BloombergFLP.CollectdWin
11 | CollectdWinService
12 | v3.5
13 | 512
14 |
15 | false
16 | publish\
17 | true
18 | Disk
19 | false
20 | Foreground
21 | 7
22 | Days
23 | false
24 | false
25 | true
26 | 2
27 | 1.0.0.%2a
28 | false
29 | true
30 | true
31 |
32 |
33 | AnyCPU
34 | true
35 | full
36 | false
37 | bin\Debug\
38 | DEBUG;TRACE
39 | prompt
40 | 4
41 |
42 |
43 | AnyCPU
44 | pdbonly
45 | true
46 | bin\Release\
47 | TRACE
48 | prompt
49 | 4
50 |
51 |
52 | true
53 | bin\x64\Debug\
54 | DEBUG;TRACE
55 | full
56 | x64
57 | prompt
58 | MinimumRecommendedRules.ruleset
59 |
60 |
61 | bin\x64\Release\
62 | TRACE
63 | true
64 | pdbonly
65 | x64
66 | prompt
67 | MinimumRecommendedRules.ruleset
68 |
69 |
70 | true
71 | bin\x86\Debug\
72 | DEBUG;TRACE
73 | full
74 | x86
75 | prompt
76 | MinimumRecommendedRules.ruleset
77 |
78 |
79 | bin\x86\Release\
80 | TRACE
81 | true
82 | pdbonly
83 | x86
84 | prompt
85 | MinimumRecommendedRules.ruleset
86 |
87 |
88 | LocalIntranet
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | ..\..\third-party\NLog.dll
98 |
99 |
100 | ..\..\third-party\RabbitMQ.Client.dll
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 | Component
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 | CollectdWinService.cs
141 |
142 |
143 |
144 |
145 | Designer
146 |
147 |
148 | Always
149 |
150 |
151 | Always
152 |
153 |
154 | Always
155 |
156 |
157 | Always
158 |
159 |
160 | Always
161 | Designer
162 |
163 |
164 | Always
165 |
166 |
167 | Always
168 |
169 |
170 |
171 |
172 | False
173 | .NET Framework 3.5 SP1 Client Profile
174 | false
175 |
176 |
177 | False
178 | .NET Framework 3.5 SP1
179 | true
180 |
181 |
182 |
183 |
184 |
185 |
186 |
193 |
--------------------------------------------------------------------------------
/src/CollectdWinService/StatsdMetrics.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text.RegularExpressions;
5 | using NLog;
6 |
7 | namespace BloombergFLP.CollectdWin
8 | {
9 | internal class StatsdMetric
10 | {
11 | public enum StatsdType
12 | {
13 | StatsdCounter,
14 | StatsdTimer,
15 | StatsdGauge,
16 | StatsdSet
17 | };
18 |
19 | private readonly HashSet _set;
20 |
21 | public StatsdMetric(string name, StatsdType type, double val)
22 | {
23 | Name = name;
24 | Type = type;
25 | _set = null;
26 | Lat = null;
27 | Value = val;
28 | NumUpdates = 1;
29 |
30 | switch (Type)
31 | {
32 | case StatsdType.StatsdSet:
33 | _set = new HashSet {val};
34 | break;
35 | case StatsdType.StatsdTimer:
36 | Lat = new Latency();
37 | Lat.Min = Lat.Max = Lat.Sum = val;
38 | Lat.Num = 1;
39 | break;
40 | }
41 | }
42 |
43 | public string Name { get; private set; }
44 | public StatsdType Type { get; private set; }
45 | public double Value { get; private set; }
46 | public Latency Lat { get; private set; }
47 | public int NumUpdates { get; private set; }
48 |
49 | public double GetMetric()
50 | {
51 | switch (Type)
52 | {
53 | case StatsdType.StatsdSet:
54 | return (_set.Count);
55 |
56 | case StatsdType.StatsdTimer:
57 | return (Lat.Sum/Lat.Num);
58 | }
59 | return (Value);
60 | }
61 |
62 | public void Reset()
63 | {
64 | NumUpdates = 0;
65 |
66 | if (Type == StatsdType.StatsdSet && _set != null)
67 | {
68 | _set.Clear();
69 | }
70 | if (Type == StatsdType.StatsdTimer && Lat != null)
71 | {
72 | Lat.Reset();
73 | }
74 | }
75 |
76 | public void AddValue(double value)
77 | {
78 | switch (Type)
79 | {
80 | case StatsdType.StatsdCounter:
81 | Value += value;
82 | break;
83 | case StatsdType.StatsdSet:
84 | _set.Add(value);
85 | break;
86 | case StatsdType.StatsdGauge:
87 | Value = value;
88 | break;
89 | case StatsdType.StatsdTimer:
90 | Lat.AddValue(value);
91 | break;
92 | }
93 | NumUpdates++;
94 | }
95 |
96 | public class Latency
97 | {
98 | public double Max;
99 | public double Min;
100 | public int Num;
101 | public double Sum;
102 |
103 | public Latency()
104 | {
105 | Min = Max = Sum = 0;
106 | Num = 0;
107 | Histogram = null;
108 | if (HistogramEnabled)
109 | {
110 | Histogram = new Histogram();
111 | }
112 | }
113 |
114 | public Histogram Histogram { get; private set; }
115 |
116 | public static bool HistogramEnabled { get; set; }
117 |
118 | public void AddValue(double val)
119 | {
120 | Min = (val < Min) ? val : Min;
121 | Max = (val > Max) ? val : Max;
122 | Sum += val;
123 | Num++;
124 | if (HistogramEnabled)
125 | {
126 | Histogram.AddValue(val);
127 | }
128 | }
129 |
130 | public void Reset()
131 | {
132 | Min = Max = Sum = 0;
133 | Num = 0;
134 | if (HistogramEnabled)
135 | {
136 | Histogram.Reset();
137 | }
138 | }
139 | };
140 | }
141 |
142 | internal class StatsdMetricParser
143 | {
144 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
145 |
146 | public static IList Parse(string str)
147 | {
148 | var metrics = new List();
149 | string[] lines = str.Split('\n');
150 | metrics.AddRange(lines.Select(ParseLine).Where(metric => metric != null));
151 | return (metrics);
152 | }
153 |
154 | /*
155 | * StatsD metric collection protocol
156 | * - metrics are separated by newlines
157 | * - each line ar generally of the form:
158 | * :|
159 | * ** Gauges : :|g
160 | * ** Counters : :|c[|@]
161 | * ** Timers : :|ms
162 | * ** Sets : :|s
163 | */
164 |
165 | public static StatsdMetric ParseLine(string line)
166 | {
167 | const string pattern = @"^(?.*):(?.*)\|(?.*)(\|\@(?.*))?$";
168 | var regex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.RightToLeft);
169 | Match match = regex.Match(line);
170 |
171 | if (!match.Success)
172 | {
173 | Logger.Debug("Parser: Invalid statsd format [{0}]", line);
174 | return (null);
175 | }
176 | GroupCollection groups = match.Groups;
177 |
178 | string name = groups["name"].Value;
179 | string valstr = groups["value"].Value;
180 | string typestr = groups["type"].Value;
181 | string ratestr = groups["rate"].Value;
182 |
183 | if (String.IsNullOrEmpty(name) || String.IsNullOrEmpty(valstr) || String.IsNullOrEmpty(typestr))
184 | {
185 | Logger.Debug("Parser: name/value/type are not optional [{0}]", line);
186 | return (null);
187 | }
188 | StatsdMetric.StatsdType type;
189 |
190 | if (String.Compare(typestr, "g", StringComparison.OrdinalIgnoreCase) == 0)
191 | type = StatsdMetric.StatsdType.StatsdGauge;
192 | else if (String.Compare(typestr, "c", StringComparison.OrdinalIgnoreCase) == 0)
193 | type = StatsdMetric.StatsdType.StatsdCounter;
194 | else if (String.Compare(typestr, "s", StringComparison.OrdinalIgnoreCase) == 0)
195 | type = StatsdMetric.StatsdType.StatsdSet;
196 | else if (String.Compare(typestr, "ms", StringComparison.OrdinalIgnoreCase) == 0)
197 | type = StatsdMetric.StatsdType.StatsdTimer;
198 | else
199 | {
200 | Logger.Debug("Parser: invalid type [{0}]", line);
201 | return (null);
202 | }
203 | double value;
204 | try
205 | {
206 | value = Convert.ToDouble(valstr);
207 | }
208 | catch (Exception)
209 | {
210 | Logger.Debug("Parser: invalid value [{0}]", line);
211 | return (null);
212 | }
213 |
214 | double rate = 0;
215 | try
216 | {
217 | if (!String.IsNullOrEmpty(ratestr))
218 | rate = Convert.ToDouble(ratestr);
219 | }
220 | catch (Exception)
221 | {
222 | Logger.Debug("Parser: invalid rate [{0}]", line);
223 | return (null);
224 | }
225 |
226 | if (!string.IsNullOrEmpty(ratestr) && (rate <= 0 || rate > 1))
227 | {
228 | Logger.Debug("Parser: invalid rate range [{0}]", line);
229 | return (null);
230 | }
231 |
232 | if (!string.IsNullOrEmpty(ratestr) && type != StatsdMetric.StatsdType.StatsdCounter)
233 | {
234 | Logger.Debug("Parser: rate is supported only for Counters [{0}]", line);
235 | return (null);
236 | }
237 |
238 | if (!string.IsNullOrEmpty(ratestr))
239 | {
240 | value = value/rate;
241 | }
242 |
243 | var metric = new StatsdMetric(name, type, value);
244 | return (metric);
245 | }
246 | }
247 | }
248 |
249 | // ----------------------------------------------------------------------------
250 | // Copyright (C) 2015 Bloomberg Finance L.P.
251 | //
252 | // Licensed under the Apache License, Version 2.0 (the "License");
253 | // you may not use this file except in compliance with the License.
254 | // You may obtain a copy of the License at
255 | // http://www.apache.org/licenses/LICENSE-2.0
256 | // Unless required by applicable law or agreed to in writing, software
257 | // distributed under the License is distributed on an "AS IS" BASIS,
258 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
259 | // See the License for the specific language governing permissions and
260 | // limitations under the License.
261 | //
262 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/MetricsCollector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Linq;
5 | using System.Threading;
6 | using System.Diagnostics;
7 | using NLog;
8 |
9 | namespace BloombergFLP.CollectdWin
10 | {
11 | internal class MetricsCollector
12 | {
13 | private const int MaxQueueSize = 30000;
14 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
15 | private readonly Aggregator _aggregator;
16 | private readonly int _interval;
17 | private readonly Queue _metricValueQueue;
18 | private readonly IList _plugins;
19 | private readonly Object _queueLock;
20 | private readonly int _timeout;
21 | private Thread _aggregatorThread;
22 | private Thread _readThread;
23 | private bool _runAggregatorThread;
24 | private bool _runReadThread, _runWriteThread;
25 | private Thread _writeThread;
26 | private IDictionary _metaData;
27 |
28 | public MetricsCollector()
29 | {
30 | var config = ConfigurationManager.GetSection("CollectdWinConfig") as CollectdWinConfig;
31 | if (config == null)
32 | {
33 | Logger.Error("Cannot get configuration section");
34 | return;
35 | }
36 |
37 | _metaData = CollectdWinConfigHelper.getMetaData();
38 |
39 | _runReadThread = false;
40 | _runWriteThread = false;
41 |
42 | var registry = new PluginRegistry();
43 | _plugins = registry.CreatePlugins();
44 |
45 | _interval = config.GeneralSettings.Interval;
46 | if (_interval <= 10)
47 | _interval = 10;
48 |
49 | _timeout = config.GeneralSettings.Timeout;
50 | if (_timeout <= _interval)
51 | _timeout = _interval*3;
52 |
53 | bool storeRates = config.GeneralSettings.StoreRates;
54 |
55 | _aggregator = new Aggregator(_timeout, storeRates);
56 |
57 | _metricValueQueue = new Queue();
58 | _queueLock = new Object();
59 | }
60 |
61 | public void ConfigureAll()
62 | {
63 | Logger.Trace("ConfigureAll() begin");
64 | foreach (IMetricsPlugin plugin in _plugins)
65 | plugin.Configure();
66 | Logger.Trace("ConfigureAll() return");
67 | }
68 |
69 | public void StartAll()
70 | {
71 | Logger.Trace("StartAll() begin");
72 | foreach (IMetricsPlugin plugin in _plugins)
73 | plugin.Start();
74 |
75 | _runWriteThread = true;
76 | _writeThread = new Thread(WriteThreadProc);
77 | _writeThread.Start();
78 |
79 | _runReadThread = true;
80 | _readThread = new Thread(ReadThreadProc);
81 | _readThread.Start();
82 |
83 | _runAggregatorThread = true;
84 | _aggregatorThread = new Thread(AggregatorThreadProc);
85 | _aggregatorThread.Start();
86 | Logger.Trace("StartAll() return");
87 | }
88 |
89 | public void StopAll()
90 | {
91 | Logger.Trace("StopAll() begin");
92 | _runReadThread = false;
93 | _runWriteThread = false;
94 | _runAggregatorThread = false;
95 |
96 | _readThread.Interrupt();
97 | _writeThread.Interrupt();
98 | _aggregatorThread.Interrupt();
99 |
100 | foreach (IMetricsPlugin plugin in _plugins)
101 | plugin.Stop();
102 | Logger.Trace("StopAll() end");
103 | }
104 |
105 | private void ReadThreadProc()
106 | {
107 | Logger.Trace("ReadThreadProc() begin");
108 | int numMetricsDropped = 0;
109 | while (_runReadThread)
110 | {
111 | try
112 | {
113 | foreach (IMetricsPlugin plugin in _plugins)
114 | {
115 | var readPlugin = plugin as IMetricsReadPlugin;
116 | if (readPlugin == null)
117 | {
118 | // skip if plugin is not a readplugin, it might be a writeplugin
119 | continue;
120 | }
121 | IList metricValues = readPlugin.Read();
122 | if (metricValues == null || !metricValues.Any())
123 | continue;
124 | lock (_queueLock)
125 | {
126 | foreach (MetricValue metric in metricValues)
127 | {
128 | _metricValueQueue.Enqueue(metric);
129 | while (_metricValueQueue.Count >= MaxQueueSize)
130 | {
131 | // When queue size grows above the Max limit,
132 | // old entries are removed
133 | _metricValueQueue.Dequeue();
134 | if ((++numMetricsDropped%1000) == 0)
135 | {
136 | Logger.Error(
137 | "Number of metrics dropped : {0}",
138 | numMetricsDropped);
139 | }
140 | }
141 | }
142 | }
143 | }
144 | Thread.Sleep(_interval*1000);
145 | }
146 | catch (Exception ex)
147 | {
148 | //Get a StackTrace object for the exception
149 | StackTrace st = new StackTrace(ex, true);
150 |
151 | Logger.Error("ReadThreadProc() got exception : {0}, {1}", ex.ToString(), st.ToString());
152 | }
153 | }
154 | Logger.Trace("ReadThreadProc() return");
155 | }
156 |
157 | private void WriteThreadProc()
158 | {
159 | Logger.Trace("WriteThreadProc() begin");
160 | bool needToFlush = false;
161 | while (_runWriteThread)
162 | {
163 | try
164 | {
165 | while (_metricValueQueue.Count > 0)
166 | {
167 | MetricValue metricValue = null;
168 | lock (_queueLock)
169 | {
170 | if (_metricValueQueue.Count > 0)
171 | metricValue = _metricValueQueue.Dequeue();
172 | }
173 | if (metricValue != null)
174 | {
175 | needToFlush = true;
176 | metricValue.Interval = _interval;
177 |
178 | _aggregator.Aggregate(ref metricValue);
179 | metricValue.AddMetaData(_metaData);
180 |
181 | foreach (IMetricsPlugin plugin in _plugins)
182 | {
183 | var writePlugin = plugin as IMetricsWritePlugin;
184 | if (writePlugin == null)
185 | {
186 | // skip if plugin is not a writeplugin, it might be a readplugin
187 | continue;
188 | }
189 | writePlugin.Write(metricValue);
190 | }
191 | }
192 | }
193 | if (needToFlush)
194 | {
195 | needToFlush = false;
196 | foreach (IMetricsPlugin plugin in _plugins)
197 | {
198 | var writePlugin = plugin as IMetricsWritePlugin;
199 | if (writePlugin != null)
200 | {
201 | // flush only if it is a Write plugin
202 | writePlugin.Flush();
203 | }
204 | }
205 | }
206 | if (_metricValueQueue.Count <= 0)
207 | {
208 | Thread.Sleep(1000);
209 | }
210 | }
211 | catch (Exception exp)
212 | {
213 | Logger.Error("WriteThreadProc() got exception : ", exp);
214 | }
215 | }
216 | Logger.Trace("WriteThreadProc() return");
217 | }
218 |
219 | private void AggregatorThreadProc()
220 | {
221 | Logger.Trace("AggregatorThreadProc() begin");
222 | while (_runAggregatorThread)
223 | {
224 | try
225 | {
226 | _aggregator.RemoveExpiredEntries();
227 | Thread.Sleep(_timeout*1000);
228 | }
229 | catch (Exception exp)
230 | {
231 | Logger.Error("AggregatorThreadProc() got exception : ", exp);
232 | }
233 | }
234 | Logger.Trace("AggregatorThreadProc() return");
235 | }
236 | }
237 | }
238 |
239 | // ----------------------------------------------------------------------------
240 | // Copyright (C) 2015 Bloomberg Finance L.P.
241 | //
242 | // Licensed under the Apache License, Version 2.0 (the "License");
243 | // you may not use this file except in compliance with the License.
244 | // You may obtain a copy of the License at
245 | // http://www.apache.org/licenses/LICENSE-2.0
246 | // Unless required by applicable law or agreed to in writing, software
247 | // distributed under the License is distributed on an "AS IS" BASIS,
248 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
249 | // See the License for the specific language governing permissions and
250 | // limitations under the License.
251 | //
252 | // ----------------------------- END-OF-FILE ----------------------------------
--------------------------------------------------------------------------------
/src/CollectdWinService/types.db:
--------------------------------------------------------------------------------
1 | #
2 | # types.db - Data-set specifications for the system statistics collection daemon collectd
3 | # This file is a copy from following URL:
4 | # https://raw.githubusercontent.com/collectd/collectd/master/src/types.db
5 | #
6 | # The types.db file contains one line for each data-set specification. Each
7 | # line consists of two fields delimited by spaces and/or horizontal tabs.
8 | # The first field defines the name of the data-set, while the second field
9 | # defines a list of data-source specifications, delimited by spaces and,
10 | # optionally, a comma (",") right after each list-entry.
11 | #
12 | # The format of the data-source specification has been inspired by RRDtool's
13 | # data-source specification. Each data-source is defined by a quadruple made
14 | # up of the data-source name, type, minimal and maximal values, delimited by
15 | # colons (":"): ds-name:ds-type:min:max. ds-type may be either ABSOLUTE,
16 | # COUNTER, DERIVE, or GAUGE. min and max define the range of valid values for
17 | # data stored for this data-source. If U is specified for either the min or
18 | # max value, it will be set to unknown, meaning that no range checks will
19 | # happen. See rrdcreate(1) for more details.
20 | #
21 | #
22 | absolute value:ABSOLUTE:0:U
23 | apache_bytes value:DERIVE:0:U
24 | apache_connections value:GAUGE:0:65535
25 | apache_idle_workers value:GAUGE:0:65535
26 | apache_requests value:DERIVE:0:U
27 | apache_scoreboard value:GAUGE:0:65535
28 | ath_nodes value:GAUGE:0:65535
29 | ath_stat value:DERIVE:0:U
30 | backends value:GAUGE:0:65535
31 | bitrate value:GAUGE:0:4294967295
32 | blocked_clients value:GAUGE:0:U
33 | bytes value:GAUGE:0:U
34 | cache_eviction value:DERIVE:0:U
35 | cache_operation value:DERIVE:0:U
36 | cache_ratio value:GAUGE:0:100
37 | cache_result value:DERIVE:0:U
38 | cache_size value:GAUGE:0:U
39 | ceph_bytes value:GAUGE:U:U
40 | ceph_latency value:GAUGE:U:U
41 | ceph_rate value:DERIVE:0:U
42 | changes_since_last_save value:GAUGE:0:U
43 | charge value:GAUGE:0:U
44 | compression_ratio value:GAUGE:0:2
45 | compression uncompressed:DERIVE:0:U, compressed:DERIVE:0:U
46 | connections value:DERIVE:0:U
47 | conntrack value:GAUGE:0:4294967295
48 | contextswitch value:DERIVE:0:U
49 | count value:GAUGE:0:U
50 | counter value:COUNTER:U:U
51 | cpufreq value:GAUGE:0:U
52 | cpu value:DERIVE:0:U
53 | current_connections value:GAUGE:0:U
54 | current_sessions value:GAUGE:0:U
55 | current value:GAUGE:U:U
56 | delay value:GAUGE:-1000000:1000000
57 | derive value:DERIVE:0:U
58 | df_complex value:GAUGE:0:U
59 | df_inodes value:GAUGE:0:U
60 | df used:GAUGE:0:1125899906842623, free:GAUGE:0:1125899906842623
61 | disk_latency read:GAUGE:0:U, write:GAUGE:0:U
62 | disk_merged read:DERIVE:0:U, write:DERIVE:0:U
63 | disk_octets read:DERIVE:0:U, write:DERIVE:0:U
64 | disk_ops_complex value:DERIVE:0:U
65 | disk_ops read:DERIVE:0:U, write:DERIVE:0:U
66 | disk_time read:DERIVE:0:U, write:DERIVE:0:U
67 | disk_io_time io_time:DERIVE:0:U, weighted_io_time:DERIVE:0:U
68 | dns_answer value:DERIVE:0:U
69 | dns_notify value:DERIVE:0:U
70 | dns_octets queries:DERIVE:0:U, responses:DERIVE:0:U
71 | dns_opcode value:DERIVE:0:U
72 | dns_qtype_cached value:GAUGE:0:4294967295
73 | dns_qtype value:DERIVE:0:U
74 | dns_query value:DERIVE:0:U
75 | dns_question value:DERIVE:0:U
76 | dns_rcode value:DERIVE:0:U
77 | dns_reject value:DERIVE:0:U
78 | dns_request value:DERIVE:0:U
79 | dns_resolver value:DERIVE:0:U
80 | dns_response value:DERIVE:0:U
81 | dns_transfer value:DERIVE:0:U
82 | dns_update value:DERIVE:0:U
83 | dns_zops value:DERIVE:0:U
84 | drbd_resource value:DERIVE:0:U
85 | duration seconds:GAUGE:0:U
86 | email_check value:GAUGE:0:U
87 | email_count value:GAUGE:0:U
88 | email_size value:GAUGE:0:U
89 | entropy value:GAUGE:0:4294967295
90 | expired_keys value:GAUGE:0:U
91 | fanspeed value:GAUGE:0:U
92 | file_size value:GAUGE:0:U
93 | files value:GAUGE:0:U
94 | flow value:GAUGE:0:U
95 | fork_rate value:DERIVE:0:U
96 | frequency_offset value:GAUGE:-1000000:1000000
97 | frequency value:GAUGE:0:U
98 | fscache_stat value:DERIVE:0:U
99 | gauge value:GAUGE:U:U
100 | hash_collisions value:DERIVE:0:U
101 | http_request_methods value:DERIVE:0:U
102 | http_requests value:DERIVE:0:U
103 | http_response_codes value:DERIVE:0:U
104 | humidity value:GAUGE:0:100
105 | if_collisions value:DERIVE:0:U
106 | if_dropped rx:DERIVE:0:U, tx:DERIVE:0:U
107 | if_errors rx:DERIVE:0:U, tx:DERIVE:0:U
108 | if_multicast value:DERIVE:0:U
109 | if_octets rx:DERIVE:0:U, tx:DERIVE:0:U
110 | if_packets rx:DERIVE:0:U, tx:DERIVE:0:U
111 | if_rx_errors value:DERIVE:0:U
112 | if_rx_octets value:DERIVE:0:U
113 | if_tx_errors value:DERIVE:0:U
114 | if_tx_octets value:DERIVE:0:U
115 | invocations value:DERIVE:0:U
116 | io_octets rx:DERIVE:0:U, tx:DERIVE:0:U
117 | io_packets rx:DERIVE:0:U, tx:DERIVE:0:U
118 | ipt_bytes value:DERIVE:0:U
119 | ipt_packets value:DERIVE:0:U
120 | irq value:DERIVE:0:U
121 | latency value:GAUGE:0:U
122 | links value:GAUGE:0:U
123 | load shortterm:GAUGE:0:5000, midterm:GAUGE:0:5000, longterm:GAUGE:0:5000
124 | md_disks value:GAUGE:0:U
125 | memcached_command value:DERIVE:0:U
126 | memcached_connections value:GAUGE:0:U
127 | memcached_items value:GAUGE:0:U
128 | memcached_octets rx:DERIVE:0:U, tx:DERIVE:0:U
129 | memcached_ops value:DERIVE:0:U
130 | memory value:GAUGE:0:281474976710656
131 | memory_lua value:GAUGE:0:281474976710656
132 | multimeter value:GAUGE:U:U
133 | mutex_operations value:DERIVE:0:U
134 | mysql_commands value:DERIVE:0:U
135 | mysql_handler value:DERIVE:0:U
136 | mysql_locks value:DERIVE:0:U
137 | mysql_log_position value:DERIVE:0:U
138 | mysql_octets rx:DERIVE:0:U, tx:DERIVE:0:U
139 | mysql_bpool_pages value:GAUGE:0:U
140 | mysql_bpool_bytes value:GAUGE:0:U
141 | mysql_bpool_counters value:DERIVE:0:U
142 | mysql_innodb_data value:DERIVE:0:U
143 | mysql_innodb_dblwr value:DERIVE:0:U
144 | mysql_innodb_log value:DERIVE:0:U
145 | mysql_innodb_pages value:DERIVE:0:U
146 | mysql_innodb_row_lock value:DERIVE:0:U
147 | mysql_innodb_rows value:DERIVE:0:U
148 | mysql_select value:DERIVE:0:U
149 | mysql_sort value:DERIVE:0:U
150 | nfs_procedure value:DERIVE:0:U
151 | nginx_connections value:GAUGE:0:U
152 | nginx_requests value:DERIVE:0:U
153 | node_octets rx:DERIVE:0:U, tx:DERIVE:0:U
154 | node_rssi value:GAUGE:0:255
155 | node_stat value:DERIVE:0:U
156 | node_tx_rate value:GAUGE:0:127
157 | objects value:GAUGE:0:U
158 | operations value:DERIVE:0:U
159 | packets value:DERIVE:0:U
160 | pending_operations value:GAUGE:0:U
161 | percent value:GAUGE:0:100.1
162 | percent_bytes value:GAUGE:0:100.1
163 | percent_inodes value:GAUGE:0:100.1
164 | pf_counters value:DERIVE:0:U
165 | pf_limits value:DERIVE:0:U
166 | pf_source value:DERIVE:0:U
167 | pf_states value:GAUGE:0:U
168 | pf_state value:DERIVE:0:U
169 | pg_blks value:DERIVE:0:U
170 | pg_db_size value:GAUGE:0:U
171 | pg_n_tup_c value:DERIVE:0:U
172 | pg_n_tup_g value:GAUGE:0:U
173 | pg_numbackends value:GAUGE:0:U
174 | pg_scan value:DERIVE:0:U
175 | pg_xact value:DERIVE:0:U
176 | ping_droprate value:GAUGE:0:100
177 | ping_stddev value:GAUGE:0:65535
178 | ping value:GAUGE:0:65535
179 | players value:GAUGE:0:1000000
180 | power value:GAUGE:0:U
181 | pressure value:GAUGE:0:U
182 | protocol_counter value:DERIVE:0:U
183 | ps_code value:GAUGE:0:9223372036854775807
184 | ps_count processes:GAUGE:0:1000000, threads:GAUGE:0:1000000
185 | ps_cputime user:DERIVE:0:U, syst:DERIVE:0:U
186 | ps_data value:GAUGE:0:9223372036854775807
187 | ps_disk_octets read:DERIVE:0:U, write:DERIVE:0:U
188 | ps_disk_ops read:DERIVE:0:U, write:DERIVE:0:U
189 | ps_pagefaults minflt:DERIVE:0:U, majflt:DERIVE:0:U
190 | ps_rss value:GAUGE:0:9223372036854775807
191 | ps_stacksize value:GAUGE:0:9223372036854775807
192 | ps_state value:GAUGE:0:65535
193 | ps_vm value:GAUGE:0:9223372036854775807
194 | pubsub value:GAUGE:0:U
195 | queue_length value:GAUGE:0:U
196 | records value:GAUGE:0:U
197 | requests value:GAUGE:0:U
198 | response_time value:GAUGE:0:U
199 | response_code value:GAUGE:0:U
200 | route_etx value:GAUGE:0:U
201 | route_metric value:GAUGE:0:U
202 | routes value:GAUGE:0:U
203 | segments value:GAUGE:0:65535
204 | serial_octets rx:DERIVE:0:U, tx:DERIVE:0:U
205 | signal_noise value:GAUGE:U:0
206 | signal_power value:GAUGE:U:0
207 | signal_quality value:GAUGE:0:U
208 | smart_poweron value:GAUGE:0:U
209 | smart_powercycles value:GAUGE:0:U
210 | smart_badsectors value:GAUGE:0:U
211 | smart_temperature value:GAUGE:-300:300
212 | smart_attribute current:GAUGE:0:255, worst:GAUGE:0:255, threshold:GAUGE:0:255, pretty:GAUGE:0:U
213 | snr value:GAUGE:0:U
214 | spam_check value:GAUGE:0:U
215 | spam_score value:GAUGE:U:U
216 | spl value:GAUGE:U:U
217 | swap_io value:DERIVE:0:U
218 | swap value:GAUGE:0:1099511627776
219 | tcp_connections value:GAUGE:0:4294967295
220 | temperature value:GAUGE:U:U
221 | threads value:GAUGE:0:U
222 | time_dispersion value:GAUGE:-1000000:1000000
223 | timeleft value:GAUGE:0:U
224 | time_offset value:GAUGE:-1000000:1000000
225 | total_bytes value:DERIVE:0:U
226 | total_connections value:DERIVE:0:U
227 | total_objects value:DERIVE:0:U
228 | total_operations value:DERIVE:0:U
229 | total_requests value:DERIVE:0:U
230 | total_sessions value:DERIVE:0:U
231 | total_threads value:DERIVE:0:U
232 | total_time_in_ms value:DERIVE:0:U
233 | total_values value:DERIVE:0:U
234 | uptime value:GAUGE:0:4294967295
235 | users value:GAUGE:0:65535
236 | vcl value:GAUGE:0:65535
237 | vcpu value:GAUGE:0:U
238 | virt_cpu_total value:DERIVE:0:U
239 | virt_vcpu value:DERIVE:0:U
240 | vmpage_action value:DERIVE:0:U
241 | vmpage_faults minflt:DERIVE:0:U, majflt:DERIVE:0:U
242 | vmpage_io in:DERIVE:0:U, out:DERIVE:0:U
243 | vmpage_number value:GAUGE:0:4294967295
244 | volatile_changes value:GAUGE:0:U
245 | voltage_threshold value:GAUGE:U:U, threshold:GAUGE:U:U
246 | voltage value:GAUGE:U:U
247 | vs_memory value:GAUGE:0:9223372036854775807
248 | vs_processes value:GAUGE:0:65535
249 | vs_threads value:GAUGE:0:65535
250 |
251 | #
252 | # Legacy types
253 | # (required for the v5 upgrade target)
254 | #
255 | arc_counts demand_data:COUNTER:0:U, demand_metadata:COUNTER:0:U, prefetch_data:COUNTER:0:U, prefetch_metadata:COUNTER:0:U
256 | arc_l2_bytes read:COUNTER:0:U, write:COUNTER:0:U
257 | arc_l2_size value:GAUGE:0:U
258 | arc_ratio value:GAUGE:0:U
259 | arc_size current:GAUGE:0:U, target:GAUGE:0:U, minlimit:GAUGE:0:U, maxlimit:GAUGE:0:U
260 | mysql_qcache hits:COUNTER:0:U, inserts:COUNTER:0:U, not_cached:COUNTER:0:U, lowmem_prunes:COUNTER:0:U, queries_in_cache:GAUGE:0:U
261 | mysql_threads running:GAUGE:0:U, connected:GAUGE:0:U, cached:GAUGE:0:U, created:COUNTER:0:U
262 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/src/CollectdWinService/WriteHttpPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.IO;
5 | using System.Net;
6 | using System.Text;
7 | using NLog;
8 | using System.Text.RegularExpressions;
9 |
10 | namespace BloombergFLP.CollectdWin
11 | {
12 | internal class WriteHttpPlugin : IMetricsWritePlugin
13 | {
14 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
15 |
16 | private readonly IList _httpWriters;
17 |
18 | public WriteHttpPlugin()
19 | {
20 | _httpWriters = new List();
21 | }
22 |
23 | public void Configure()
24 | {
25 | var config = ConfigurationManager.GetSection("WriteHttp") as WriteHttpPluginConfig;
26 | if (config == null)
27 | {
28 | throw new Exception("Cannot get configuration section : WriteHttp");
29 | }
30 |
31 | _httpWriters.Clear();
32 |
33 | foreach (WriteHttpPluginConfig.WriteHttpNodeConfig node in config.Nodes)
34 | {
35 | var writer = new HttpWriter
36 | {
37 | Url = node.Url,
38 | Timeout = node.Timeout,
39 | BatchSize = node.BatchSize,
40 | MaxIdleTime = node.MaxIdleTime,
41 | EnableProxy = node.Proxy.Enable
42 | };
43 |
44 | if (writer.EnableProxy)
45 | {
46 | writer.WebProxy = node.Proxy.Url.Length > 0 ? new WebProxy(node.Proxy.Url) : new WebProxy();
47 | }
48 |
49 | if (!string.IsNullOrEmpty(node.UserName) && !string.IsNullOrEmpty(node.Password))
50 | {
51 | /* Possibly misfeature- adding BasicAuthHeaderData to HttpWriter class to efficiently support basic auth,
52 | * but saves the ToBase64String string encode on each request. Better, but more expensive, would be
53 | * to put both on as secure strings and add a config param to support other auth methods while
54 | * building the HttpWebResponse on each call. @FerventGeek */
55 | writer.BasicAuthHeaderData = System.Convert.ToBase64String(
56 | System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(node.UserName + ":" + node.Password));
57 | Logger.Info("Using BasicAuth for node {0}, user {1}", node.Name, node.UserName);
58 | }
59 |
60 | if (!string.IsNullOrEmpty(node.SafeCharsRegex))
61 | {
62 | // compile for perfomace, since config is only loaded on start
63 | writer.SafeCharsRegex = new Regex("[^" + node.SafeCharsRegex + "]", RegexOptions.Compiled);
64 | Logger.Info("Using SafeChars for node {0}, regex \"{1}\" replaced with \"{2}\"",
65 | node.Name, writer.SafeCharsRegex.ToString(), node.ReplaceWith);
66 | }
67 |
68 | if (node.ReplaceWith == null)
69 | {
70 | // default, strip unsafe chars
71 | writer.ReplaceWith = "";
72 | }
73 | else
74 | {
75 | writer.ReplaceWith = node.ReplaceWith;
76 | }
77 |
78 | _httpWriters.Add(writer);
79 | }
80 |
81 | Logger.Info("WriteHttp plugin configured");
82 | }
83 |
84 | public void Flush()
85 | {
86 | foreach (HttpWriter writer in _httpWriters)
87 | {
88 | writer.Flush();
89 | }
90 | }
91 |
92 | public void Start()
93 | {
94 | Logger.Info("WriteHttp - plugin started");
95 | }
96 |
97 | public void Stop()
98 | {
99 | Logger.Info("WriteHttp - plugin stopped");
100 | }
101 |
102 | public void Write(MetricValue metric)
103 | {
104 | if (metric == null)
105 | {
106 | Logger.Debug("write() - Invalid null metric");
107 | return;
108 | }
109 | foreach (HttpWriter writer in _httpWriters)
110 | {
111 | writer.Write(metric);
112 | }
113 | }
114 | }
115 |
116 | internal class HttpWriter
117 | {
118 | private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
119 |
120 | public int BatchSize = 20;
121 | public bool EnableProxy = false;
122 | public int MaxIdleTime;
123 | public int Timeout;
124 | public string Url;
125 | public WebProxy WebProxy = null;
126 | public string BasicAuthHeaderData = null;
127 | public Regex SafeCharsRegex = null;
128 | public string ReplaceWith = null;
129 |
130 | private StringBuilder _batchedMetricStr;
131 | private int _numMetrics;
132 | private int _numSequentialHttpFailures = 0;
133 |
134 | private void publish()
135 | {
136 | if (_batchedMetricStr != null)
137 | {
138 | _batchedMetricStr.Append("]");
139 | HttpPost(_batchedMetricStr.ToString());
140 | _batchedMetricStr = null;
141 | _numMetrics = 0;
142 | }
143 | }
144 |
145 | public void Write(MetricValue metric)
146 | {
147 | // Optional Regex replace of unsafe chars
148 | if (SafeCharsRegex != null)
149 | {
150 | metric.PluginInstanceName = SafeCharsRegex.Replace(metric.PluginInstanceName, ReplaceWith);
151 | }
152 |
153 | string message = metric.GetMetricJsonStr();
154 |
155 | if (_batchedMetricStr == null)
156 | {
157 | _batchedMetricStr = new StringBuilder("[").Append(message);
158 | }
159 | else
160 | {
161 | _batchedMetricStr.Append(",").Append(message);
162 | }
163 | _numMetrics++;
164 |
165 | if (_numMetrics < BatchSize) return;
166 |
167 | publish();
168 | }
169 |
170 | public void Flush()
171 | {
172 | publish();
173 | }
174 |
175 | public void HttpPost(string metricJsonStr)
176 | {
177 | HttpWebResponse response = null;
178 | try
179 | {
180 | byte[] data = Encoding.UTF8.GetBytes(metricJsonStr);
181 | var request = (HttpWebRequest) WebRequest.Create(Url);
182 |
183 | request.Method = "POST";
184 | request.ContentType = "application/json";
185 | request.ContentLength = data.Length;
186 | request.UserAgent = "CollectdWin/1.0";
187 | request.Accept = "*/*";
188 | request.KeepAlive = true;
189 | request.Timeout = Timeout;
190 |
191 | if (EnableProxy)
192 | {
193 | request.Proxy = WebProxy;
194 | }
195 | if (MaxIdleTime > 0)
196 | {
197 | request.ServicePoint.MaxIdleTime = MaxIdleTime;
198 | }
199 | // Optional do BasicAuth for POST
200 | if (BasicAuthHeaderData != null)
201 | {
202 | request.Headers.Add("Authorization", "Basic " + BasicAuthHeaderData);
203 | }
204 |
205 | // Display service point properties.
206 | Logger.Trace("Connection properties: ServicePoint - HashCode:{0}, MaxIdleTime:{1}, IdleSince:{2}",
207 | request.ServicePoint.GetHashCode(), request.ServicePoint.MaxIdleTime, request.ServicePoint.IdleSince);
208 |
209 | using (Stream reqStream = request.GetRequestStream())
210 | {
211 | if (Logger.IsTraceEnabled)
212 | {
213 | Logger.Trace("Adding request body : {0}", metricJsonStr);
214 | }
215 |
216 | reqStream.Write(data, 0, data.Length);
217 | }
218 |
219 | response = (HttpWebResponse) request.GetResponse();
220 |
221 | // Skip overhead of the trace body read
222 | if (Logger.IsTraceEnabled)
223 | {
224 | Stream respStream = response.GetResponseStream();
225 | string responseString = new StreamReader(respStream).ReadToEnd();
226 | Logger.Trace("Got response : {0} - {1} : {2}",
227 | (int)response.StatusCode, response.StatusCode, responseString);
228 | }
229 | _numSequentialHttpFailures = 0;
230 | }
231 | catch (WebException ex)
232 | {
233 | _numSequentialHttpFailures += 1;
234 |
235 | const int errThreshold = 3;
236 | LogLevel logLevel = _numSequentialHttpFailures > errThreshold ? LogLevel.Error
237 | : LogLevel.Warn;
238 | if (ex.Status == WebExceptionStatus.ProtocolError)
239 | {
240 | HttpWebResponse exceptionResponse = (HttpWebResponse)ex.Response;
241 |
242 | Logger.Log(logLevel, "Got web exception in http post : {0} - {1}",
243 | (int)exceptionResponse.StatusCode, exceptionResponse.StatusCode);
244 |
245 | if (Logger.IsTraceEnabled)
246 | {
247 | // Skip overhead of trace body read
248 | using (var stream = exceptionResponse.GetResponseStream())
249 | using (var reader = new StreamReader(stream))
250 | {
251 | string errorBody = reader.ReadToEnd();
252 | if (errorBody != null)
253 | {
254 | Logger.Trace(errorBody);
255 | }
256 | }
257 | }
258 | }
259 | else
260 | {
261 | Logger.Log(logLevel, "Got web exception in http post : {0}", ex.ToString());
262 | }
263 | }
264 | catch (Exception exp)
265 | {
266 | Logger.Error("Got exception in http post : {0}", exp);
267 | }
268 | finally
269 | {
270 | if (response != null)
271 | {
272 | response.Close();
273 | }
274 | }
275 | }
276 | }
277 | }
278 |
279 | // ----------------------------------------------------------------------------
280 | // Copyright (C) 2015 Bloomberg Finance L.P.
281 | //
282 | // Licensed under the Apache License, Version 2.0 (the "License");
283 | // you may not use this file except in compliance with the License.
284 | // You may obtain a copy of the License at
285 | // http://www.apache.org/licenses/LICENSE-2.0
286 | // Unless required by applicable law or agreed to in writing, software
287 | // distributed under the License is distributed on an "AS IS" BASIS,
288 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
289 | // See the License for the specific language governing permissions and
290 | // limitations under the License.
291 | //
292 | // ----------------------------- END-OF-FILE ----------------------------------
293 |
--------------------------------------------------------------------------------