diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..24d319c --- /dev/null +++ b/.gitignore @@ -0,0 +1,184 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +*.log +*.orig + + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.azurePubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +packages/ +## TODO: If the tool you use requires repositories.config, also uncomment the next line +#!packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ \ No newline at end of file diff --git a/Cat.Net.csproj b/Cat.Net.csproj index a8b32cd..8d038f9 100644 --- a/Cat.Net.csproj +++ b/Cat.Net.csproj @@ -1,94 +1,100 @@ - - - - Debug - x86 - 10.0.0 - 2.0 - {7B5F7994-F1D1-494D-85B9-935A478591AD} - Library - Com.Dianping.Cat - Cat - 0.1.1 - false - Cat .Net Client - v4.0 - - - - true - full - false - bin\Debug\ - DEBUG; - prompt - 4 - AnyCPU - true - - - none - true - bin\Release\ - prompt - 4 - AnyCPU - true - - - - - - - - - - Code - - - - - - - - - - Code - - - - Code - - - - - Code - - - - - - - - - - - - - - - - Code - - - - - - - - - - - - + + + + Debug + x86 + 10.0.0 + 2.0 + {7B5F7994-F1D1-494D-85B9-935A478591AD} + Library + Com.Dianping.Cat + Cat + 0.1.1 + false + Cat .Net Client + v4.0 + + + + true + full + false + bin\Debug\ + DEBUG; + prompt + 4 + AnyCPU + true + + + none + true + bin\Release\ + prompt + 4 + AnyCPU + true + + + + + + + + + + + + Code + + + + + + + + + + + + + + Code + + + + Code + + + + + Code + + + + + + + + + + + + + + + + Code + + + + + + + + + + + + \ No newline at end of file diff --git a/Cat.Net.csproj.user b/Cat.Net.csproj.user deleted file mode 100644 index 55f44b9..0000000 --- a/Cat.Net.csproj.user +++ /dev/null @@ -1,6 +0,0 @@ - - - - ShowAllFiles - - \ No newline at end of file diff --git a/Cat.Net.sln.DotSettings.user b/Cat.Net.sln.DotSettings.user deleted file mode 100644 index 8641e71..0000000 --- a/Cat.Net.sln.DotSettings.user +++ /dev/null @@ -1,2 +0,0 @@ - - False \ No newline at end of file diff --git a/Cat.Net.suo b/Cat.Net.suo deleted file mode 100644 index 2667299..0000000 Binary files a/Cat.Net.suo and /dev/null differ diff --git a/Cat.cs b/Cat.cs index dbd6510..28bc714 100644 --- a/Cat.cs +++ b/Cat.cs @@ -1,193 +1,258 @@ -using Com.Dianping.Cat.Configuration; -using Com.Dianping.Cat.Message.Spi; -using System.Collections.Generic; -using System.IO; -using System.Xml; -using System.Linq; -using Com.Dianping.Cat.Message.Spi.Internals; -using Com.Dianping.Cat.Util; - -namespace Com.Dianping.Cat -{ - public class Cat - { - private static readonly Cat Instance = new Cat(); - - private bool _mInitialized; - - private IMessageManager _mManager; - - private IMessageProducer _mProducer; - - private Cat() - { - } - - public static IMessageManager GetManager() - { - return Instance._mManager; - } - - public static IMessageProducer GetProducer() - { - return Instance._mProducer; - } - - public static void Initialize(string configFile) - { - if (Instance._mInitialized) - { - Logger.Warn("Cat can't initialize again with config file(%s), IGNORED!", configFile); - return; - } - - Logger.Info("Initializing Cat .Net Client ..."); - - DefaultMessageManager manager = new DefaultMessageManager(); - ClientConfig clientConfig = LoadClientConfig(configFile); - - manager.InitializeClient(clientConfig); - Instance._mProducer = new DefaultMessageProducer(manager); - Instance._mManager = manager; - Instance._mInitialized = true; - - Logger.Info("Cat .Net Client initialized."); - } - - public static bool IsInitialized() - { - return Instance._mInitialized; - } - - private static ClientConfig LoadClientConfig(string configFile) - { - ClientConfig config = new ClientConfig(); - - if (File.Exists(configFile)) - { - Logger.Info("Use config file({0}).", configFile); - - XmlDocument doc = new XmlDocument(); - - doc.Load(configFile); - - XmlElement root = doc.DocumentElement; - - if (root != null) - { - config.Domain = BuildDomain(root.GetElementsByTagName("domain")); - - IEnumerable servers = BuildServers(root.GetElementsByTagName("servers")); - - //NOTE: 只添加Enabled的 - foreach (Server server in servers.Where(server => server.Enabled)) - { - config.Servers.Add(server); - Logger.Info("CAT server configured: {0}:{1}", server.Ip, server.Port); - } - } - } - else - { - Logger.Warn("Config file({0}) not found, using localhost:2280 instead.", configFile); - - config.Domain = BuildDomain(null); - config.Servers.Add(new Server("localhost", 2280)); - } - - return config; - } - - private static Domain BuildDomain(XmlNodeList nodes) - { - if (nodes == null || nodes.Count == 0) - { - return new Domain(); - } - - XmlElement node = (XmlElement) nodes[0]; - return new Domain - { - Id = GetStringProperty(node, "id", "Unknown"), - //Ip = GetStringProperty(node, "ip", null), - Enabled = GetBooleanProperty(node, "enabled", true) - }; - } - - private static IEnumerable BuildServers(XmlNodeList nodes) - { - List servers = new List(); - - if (nodes != null && nodes.Count > 0) - { - XmlElement first = (XmlElement) nodes[0]; - XmlNodeList serverNodes = first.GetElementsByTagName("server"); - - foreach (XmlNode node in serverNodes) - { - XmlElement serverNode = (XmlElement) node; - string ip = GetStringProperty(serverNode, "ip", "localhost"); - int port = GetIntProperty(serverNode, "port", 2280); - Server server = new Server(ip, port) {Enabled = GetBooleanProperty(serverNode, "enabled", true)}; - - servers.Add(server); - } - } - - if (servers.Count == 0) - { - Logger.Warn("No server configured, use localhost:2280 instead."); - servers.Add(new Server("localhost", 2280)); - } - - return servers; - } - - private static string GetStringProperty(XmlElement element, string name, string defaultValue) - { - if (element != null) - { - string value = element.GetAttribute(name); - - if (value.Length > 0) - { - return value; - } - } - - return defaultValue; - } - - private static bool GetBooleanProperty(XmlElement element, string name, bool defaultValue) - { - if (element != null) - { - string value = element.GetAttribute(name); - - if (value.Length > 0) - { - return "true".Equals(value); - } - } - - return defaultValue; - } - - private static int GetIntProperty(XmlElement element, string name, int defaultValue) - { - if (element != null) - { - string value = element.GetAttribute(name); - - if (value.Length > 0) - { - int tmpRet; - if (int.TryParse(value, out tmpRet)) - return tmpRet; - } - } - - return defaultValue; - } - } +using Com.Dianping.Cat.Configuration; +using Com.Dianping.Cat.Message; +using Com.Dianping.Cat.Message.Spi; +using Com.Dianping.Cat.Message.Spi.Internals; +using Com.Dianping.Cat.Util; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; + +namespace Com.Dianping.Cat +{ + public class Cat + { + private static readonly Cat Instance = new Cat(); + + private bool _mInitialized; + + private IMessageManager _mManager; + + private IMessageProducer _mProducer; + + private Cat() + { + } + + public static IMessageManager GetManager() + { + return Instance._mManager; + } + + public static IMessageProducer GetProducer() + { + return Instance._mProducer; + } + + public static void Initialize(string configFile = null) + { + if (string.IsNullOrWhiteSpace(configFile)) + configFile = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "App_Data\\TCConfig\\CatConfig.xml"); + if (Instance._mInitialized) + { + Logger.Warn("Cat can't initialize again with config file(%s), IGNORED!", configFile); + return; + } + + Logger.Info("Initializing Cat .Net Client ..."); + + DefaultMessageManager manager = new DefaultMessageManager(); + ClientConfig clientConfig = LoadClientConfig(configFile); + + manager.InitializeClient(clientConfig); + Instance._mProducer = new DefaultMessageProducer(manager); + Instance._mManager = manager; + Instance._mInitialized = true; + Logger.Info("Cat .Net Client initialized."); + } + + public static bool IsInitialized() + { + bool isInitialized = Instance._mInitialized; + if (isInitialized && !Instance._mManager.HasContext()) + { + Instance._mManager.Setup(); + } + return isInitialized; + } + + #region Log + + public static void LogError(Exception ex) + { + Cat.GetProducer().LogError(ex); + } + + public static void LogEvent(string type, string name, string status = "0", string nameValuePairs = null) + { + Cat.GetProducer().LogEvent(type, name, status, nameValuePairs); + } + + public static void LogHeartbeat(string type, string name, string status = "0", string nameValuePairs = null) + { + Cat.GetProducer().LogHeartbeat(type, name, status, nameValuePairs); + } + + public static void LogMetricForCount(string name, int quantity = 1) + { + LogMetricInternal(name, "C", quantity.ToString()); + } + + public static void LogMetricForDuration(string name, double value) + { + LogMetricInternal(name, "T", String.Format("{0:F}", value)); + } + + public static void LogMetricForSum(string name, double sum, int quantity) + { + LogMetricInternal(name, "S,C", String.Format("{0},{1:F}", quantity, sum)); + } + + private static void LogMetricInternal(string name, string status, string keyValuePairs = null) + { + Cat.GetProducer().LogMetric(name, status, keyValuePairs); + } + + #endregion + + #region New message + + public static IEvent NewEvent(string type, string name) + { + return Cat.GetProducer().NewEvent(type, name); + } + + public static ITransaction NewTransaction(string type, string name) + { + return Cat.GetProducer().NewTransaction(type, name); + } + #endregion + + #region 配置文件属性获取 + + private static ClientConfig LoadClientConfig(string configFile) + { + ClientConfig config = new ClientConfig(); + + if (File.Exists(configFile)) + { + Logger.Info("Use config file({0}).", configFile); + + XmlDocument doc = new XmlDocument(); + + doc.Load(configFile); + + XmlElement root = doc.DocumentElement; + + if (root != null) + { + config.Domain = BuildDomain(root.GetElementsByTagName("domain")); + + IEnumerable servers = BuildServers(root.GetElementsByTagName("servers")); + + //NOTE: 只添加Enabled的 + foreach (Server server in servers.Where(server => server.Enabled)) + { + config.Servers.Add(server); + Logger.Info("CAT server configured: {0}:{1}", server.Ip, server.Port); + } + } + } + else + { + Logger.Warn("Config file({0}) not found.", configFile); + //Logger.Warn("Config file({0}) not found, using localhost:2280 instead.", configFile); + + //config.Domain = BuildDomain(null); + //config.Servers.Add(new Server("localhost", 2280)); + } + + return config; + } + + private static Domain BuildDomain(XmlNodeList nodes) + { + if (nodes == null || nodes.Count == 0) + { + return new Domain(); + } + + XmlElement node = (XmlElement)nodes[0]; + return new Domain + { + Id = GetStringProperty(node, "id", "Unknown"), + //Ip = GetStringProperty(node, "ip", null), + Enabled = GetBooleanProperty(node, "enabled", false) + }; + } + + private static IEnumerable BuildServers(XmlNodeList nodes) + { + List servers = new List(); + + if (nodes != null && nodes.Count > 0) + { + XmlElement first = (XmlElement)nodes[0]; + XmlNodeList serverNodes = first.GetElementsByTagName("server"); + + foreach (XmlNode node in serverNodes) + { + XmlElement serverNode = (XmlElement)node; + string ip = GetStringProperty(serverNode, "ip", "localhost"); + int port = GetIntProperty(serverNode, "port", 2280); + Server server = new Server(ip, port) { Enabled = GetBooleanProperty(serverNode, "enabled", true) }; + + servers.Add(server); + } + } + + if (servers.Count == 0) + { + Logger.Warn("No server configured, use localhost:2280 instead."); + servers.Add(new Server("localhost", 2280)); + } + + return servers; + } + + private static string GetStringProperty(XmlElement element, string name, string defaultValue) + { + if (element != null) + { + string value = element.GetAttribute(name); + + if (value.Length > 0) + { + return value; + } + } + + return defaultValue; + } + + private static bool GetBooleanProperty(XmlElement element, string name, bool defaultValue) + { + if (element != null) + { + string value = element.GetAttribute(name); + + if (value.Length > 0) + { + return "true".Equals(value); + } + } + + return defaultValue; + } + + private static int GetIntProperty(XmlElement element, string name, int defaultValue) + { + if (element != null) + { + string value = element.GetAttribute(name); + + if (value.Length > 0) + { + int tmpRet; + if (int.TryParse(value, out tmpRet)) + return tmpRet; + } + } + + return defaultValue; + } + #endregion + + } } \ No newline at end of file diff --git a/Configuration/ClientConfig.cs b/Configuration/ClientConfig.cs index 86e7bf3..4131072 100644 --- a/Configuration/ClientConfig.cs +++ b/Configuration/ClientConfig.cs @@ -1,38 +1,38 @@ -using System.Collections.Generic; - -namespace Com.Dianping.Cat.Configuration -{ - /// - /// Cat客户端配置 - /// - public class ClientConfig - { - private readonly IList _mServers; - private Domain _mDomain; - - public ClientConfig() - { - _mServers = new List(); - } - - /// - /// 是否是开发模式 - /// - public bool DevMode { get; set; } - - public Domain Domain - { - get { return _mDomain ?? (_mDomain = new Domain()); } - - set { _mDomain = value; } - } - - /// - /// Cat日志服务器,可以有多个 - /// - public IList Servers - { - get { return _mServers; } - } - } +using System.Collections.Generic; + +namespace Com.Dianping.Cat.Configuration +{ + /// + /// Cat客户端配置 + /// + public class ClientConfig + { + private readonly IList _mServers; + private Domain _mDomain; + + public ClientConfig() + { + _mServers = new List(); + } + + /// + /// 是否是开发模式 + /// + public bool DevMode { get; set; } + + public Domain Domain + { + get { return _mDomain ?? (_mDomain = new Domain()); } + + set { _mDomain = value; } + } + + /// + /// Cat日志服务器,可以有多个 + /// + public IList Servers + { + get { return _mServers; } + } + } } \ No newline at end of file diff --git a/Configuration/Domain.cs b/Configuration/Domain.cs index 63368ae..8c13f63 100644 --- a/Configuration/Domain.cs +++ b/Configuration/Domain.cs @@ -1,34 +1,34 @@ -namespace Com.Dianping.Cat.Configuration -{ - /// - /// 描述当前系统的情况 - /// - public class Domain - { - private string _id = "Unknown"; - private bool _mEnabled = true; - - /// - /// 当前系统的标识 - /// - public string Id - { - get { return _id; } - set { _id = value; } - } - - ///// - ///// 当前系统的IP - ///// - //public string Ip { get; set; } - - /// - /// Cat日志是否开启,默认开启 - /// - public bool Enabled - { - get { return _mEnabled; } - set { _mEnabled = value; } - } - } +namespace Com.Dianping.Cat.Configuration +{ + /// + /// 描述当前系统的情况 + /// + public class Domain + { + private string _id = "Unknown"; + private bool _mEnabled = false; + + /// + /// 当前系统的标识 + /// + public string Id + { + get { return _id; } + set { _id = value; } + } + + ///// + ///// 当前系统的IP + ///// + //public string Ip { get; set; } + + /// + /// Cat日志是否开启,默认关闭 + /// + public bool Enabled + { + get { return _mEnabled; } + set { _mEnabled = value; } + } + } } \ No newline at end of file diff --git a/Configuration/Server.cs b/Configuration/Server.cs index 5dfebf5..3c01809 100644 --- a/Configuration/Server.cs +++ b/Configuration/Server.cs @@ -1,40 +1,40 @@ -namespace Com.Dianping.Cat.Configuration -{ - /// - /// 描述记录当前系统日志的目标Cat服务器 - /// - public class Server - { - private readonly string _mIp; - - private readonly int _mPort; - - public Server(string ip, int port) - { - _mIp = ip; - _mPort = port; - Enabled = true; - } - - /// - /// Cat服务器IP - /// - public string Ip - { - get { return _mIp; } - } - - /// - /// Cat服务器端口 - /// - public int Port - { - get { return _mPort; } - } - - /// - /// Cat服务器是否有效,默认有效 - /// - public bool Enabled { get; set; } - } +namespace Com.Dianping.Cat.Configuration +{ + /// + /// 描述记录当前系统日志的目标Cat服务器 + /// + public class Server + { + private readonly string _mIp; + + private readonly int _mPort; + + public Server(string ip, int port) + { + _mIp = ip; + _mPort = port; + Enabled = true; + } + + /// + /// Cat服务器IP + /// + public string Ip + { + get { return _mIp; } + } + + /// + /// Cat服务器端口 + /// + public int Port + { + get { return _mPort; } + } + + /// + /// Cat服务器是否有效,默认有效 + /// + public bool Enabled { get; set; } + } } \ No newline at end of file diff --git a/Message/IEvent.cs b/Message/IEvent.cs index 21f006c..e8577fe 100644 --- a/Message/IEvent.cs +++ b/Message/IEvent.cs @@ -1,21 +1,21 @@ -namespace Com.Dianping.Cat.Message -{ - /// - ///

- /// Event - /// is used to log anything interesting happens at a specific - /// time. Such as an exception thrown, a review added by user, a new user - /// registered, an user logged into the system etc.

However, if it could be failure, or last for a long time, such as a remote - /// API call, database call or search engine call etc. It should be logged as a - /// Transaction - ///

All CAT message will be constructed as a message tree and send to back-end - /// for further analysis, and for monitoring. Only - /// Transaction - /// can - /// be a tree node, all other message will be the tree leaf.?The transaction - /// without other messages nested is an atomic transaction.

- ///
- public interface IEvent : IMessage - { - } +namespace Com.Dianping.Cat.Message +{ + /// + ///

+ /// Event + /// is used to log anything interesting happens at a specific + /// time. Such as an exception thrown, a review added by user, a new user + /// registered, an user logged into the system etc.

However, if it could be failure, or last for a long time, such as a remote + /// API call, database call or search engine call etc. It should be logged as a + /// Transaction + ///

All CAT message will be constructed as a message tree and send to back-end + /// for further analysis, and for monitoring. Only + /// Transaction + /// can + /// be a tree node, all other message will be the tree leaf.?The transaction + /// without other messages nested is an atomic transaction.

+ ///
+ public interface IEvent : IMessage + { + } } \ No newline at end of file diff --git a/Message/IHeartbeat.cs b/Message/IHeartbeat.cs index 290c473..addae00 100644 --- a/Message/IHeartbeat.cs +++ b/Message/IHeartbeat.cs @@ -1,27 +1,27 @@ -namespace Com.Dianping.Cat.Message -{ - /// - ///

- /// Heartbeat - /// is used to log data that happens in a regular - /// intervals, for example once per second, such as system load, CPU percentage, - /// memory usage, thread pool statistics, cache hit/miss rate, service manifest - /// etc., and even some configuration could be carried by - /// Heartbeat - /// . - /// There could be some good use cases, for example health checker and load - /// balancer, that make good use of it.

- /// Heartbeat - /// should never be used per request since the request is - /// not regular predictable, instead it could be logged in a daemon background - /// thread, or something like a Timer.

All CAT message will be constructed as a message tree and send to back-end - /// for further analysis, and for monitoring. Only - /// Transaction - /// can - /// be a tree node, all other message will be the tree leaf.?The transaction - /// without other messages nested is an atomic transaction.

- ///
- public interface IHeartbeat : IMessage - { - } +namespace Com.Dianping.Cat.Message +{ + /// + ///

+ /// Heartbeat + /// is used to log data that happens in a regular + /// intervals, for example once per second, such as system load, CPU percentage, + /// memory usage, thread pool statistics, cache hit/miss rate, service manifest + /// etc., and even some configuration could be carried by + /// Heartbeat + /// . + /// There could be some good use cases, for example health checker and load + /// balancer, that make good use of it.

+ /// Heartbeat + /// should never be used per request since the request is + /// not regular predictable, instead it could be logged in a daemon background + /// thread, or something like a Timer.

All CAT message will be constructed as a message tree and send to back-end + /// for further analysis, and for monitoring. Only + /// Transaction + /// can + /// be a tree node, all other message will be the tree leaf.?The transaction + /// without other messages nested is an atomic transaction.

+ ///
+ public interface IHeartbeat : IMessage + { + } } \ No newline at end of file diff --git a/Message/IMessage.cs b/Message/IMessage.cs index 4deae9f..cb06003 100644 --- a/Message/IMessage.cs +++ b/Message/IMessage.cs @@ -1,108 +1,108 @@ -using System; - -namespace Com.Dianping.Cat.Message -{ - /** - *

- * Message represents data collected during application runtime. It will be sent - * to back-end system asynchronous for further processing. - *

- * - *

- * Super interface of Event, Heartbeat and - * Transaction. - *

- * - * @see Event, Heartbeat, Transaction - * @author Frankie Wu - */ - - public interface IMessage - { - /** - * @return key value pairs data - */ - string Data { get; } - - /** - * Message name. - * - * @return message name - */ - string Name { get; } - - /** - * Get the message status. - * - * @return message status. "0" means success, otherwise error code. - */ - string Status { get; set; } - - /** - * The time stamp the message was created. - * - * @return message creation time stamp in milliseconds - */ - long Timestamp { get; set; } - - /** - * Message type. - * - *

- * Typical message types are: - *

    - *
  • URL: maps to one method of an action
  • - *
  • Service: maps to one method of service call
  • - *
  • Search: maps to one method of search call
  • - *
  • SQL: maps to one SQL statement
  • - *
  • Cache: maps to one cache access
  • - *
  • Error: maps to java.lang.Throwable (java.lang.Exception and java.lang.Error)
  • - *
- *

- * - * @return message type - */ - string Type { get; } - - /** - * add one or multiple key-value pairs to the message. - * - * @param keyValuePairs - * key-value pairs like 'a=1&b=2&...' - */ - void AddData(String keyValuePairs); - - /** - * add one key-value pair to the message. - * - * @param key - * @param value - */ - void AddData(String key, Object value); - - /** - * Complete the message construction. - */ - void Complete(); - - /** - * If the complete() method was called or not. - * - * @return true means the complete() method was called, false otherwise. - */ - bool IsCompleted(); - - /** - * @return - */ - bool IsSuccess(); - - /** - * Set the message status with exception class name. - * - * @param e - * exception. - */ - void SetStatus(Exception e); - } +using System; + +namespace Com.Dianping.Cat.Message +{ + /** + *

+ * Message represents data collected during application runtime. It will be sent + * to back-end system asynchronous for further processing. + *

+ * + *

+ * Super interface of Event, Heartbeat and + * Transaction. + *

+ * + * @see Event, Heartbeat, Transaction + * @author Frankie Wu + */ + + public interface IMessage + { + /** + * @return key value pairs data + */ + string Data { get; } + + /** + * Message name. + * + * @return message name + */ + string Name { get; } + + /** + * Get the message status. + * + * @return message status. "0" means success, otherwise error code. + */ + string Status { get; set; } + + /** + * The time stamp the message was created. + * + * @return message creation time stamp in milliseconds + */ + long Timestamp { get; set; } + + /** + * Message type. + * + *

+ * Typical message types are: + *

    + *
  • URL: maps to one method of an action
  • + *
  • Service: maps to one method of service call
  • + *
  • Search: maps to one method of search call
  • + *
  • SQL: maps to one SQL statement
  • + *
  • Cache: maps to one cache access
  • + *
  • Error: maps to java.lang.Throwable (java.lang.Exception and java.lang.Error)
  • + *
+ *

+ * + * @return message type + */ + string Type { get; } + + /** + * add one or multiple key-value pairs to the message. + * + * @param keyValuePairs + * key-value pairs like 'a=1&b=2&...' + */ + void AddData(String keyValuePairs); + + /** + * add one key-value pair to the message. + * + * @param key + * @param value + */ + void AddData(String key, Object value); + + /** + * Complete the message construction. + */ + void Complete(); + + /** + * If the complete() method was called or not. + * + * @return true means the complete() method was called, false otherwise. + */ + bool IsCompleted(); + + /** + * @return + */ + bool IsSuccess(); + + /** + * Set the message status with exception class name. + * + * @param e + * exception. + */ + void SetStatus(Exception e); + } } \ No newline at end of file diff --git a/Message/IMessageTree.cs b/Message/IMessageTree.cs index 78f8f2f..b9a75e7 100644 --- a/Message/IMessageTree.cs +++ b/Message/IMessageTree.cs @@ -1,41 +1,41 @@ -using System; - -namespace Com.Dianping.Cat.Message -{ - public interface IMessageTree - { - String Domain { get; set; } - - - String HostName { get; set; } - - - String IpAddress { get; set; } - - - IMessage Message { get; set; } - - - String MessageId { get; set; } - - - String ParentMessageId { get; set; } - - - String RootMessageId { get; set; } - - - String SessionToken { get; set; } - - - String ThreadGroupName { get; set; } - - - String ThreadId { get; set; } - - - String ThreadName { get; set; } - - IMessageTree Copy(); - } +using System; + +namespace Com.Dianping.Cat.Message +{ + public interface IMessageTree + { + String Domain { get; set; } + + + String HostName { get; set; } + + + String IpAddress { get; set; } + + + IMessage Message { get; set; } + + + String MessageId { get; set; } + + + String ParentMessageId { get; set; } + + + String RootMessageId { get; set; } + + + String SessionToken { get; set; } + + + String ThreadGroupName { get; set; } + + + String ThreadId { get; set; } + + + String ThreadName { get; set; } + + IMessageTree Copy(); + } } \ No newline at end of file diff --git a/Message/IMetric.cs b/Message/IMetric.cs new file mode 100644 index 0000000..3ef0947 --- /dev/null +++ b/Message/IMetric.cs @@ -0,0 +1,6 @@ +namespace Com.Dianping.Cat.Message +{ + public interface IMetric : IMessage + { + } +} diff --git a/Message/ITransaction.cs b/Message/ITransaction.cs index 21973e4..ac8813c 100644 --- a/Message/ITransaction.cs +++ b/Message/ITransaction.cs @@ -1,94 +1,94 @@ -using System.Collections.Generic; - -namespace Com.Dianping.Cat.Message -{ - /** - *

- * Transaction is any interesting unit of work that takes time to - * complete and may fail. - *

- * - *

- * Basically, all data access across the boundary needs to be logged as a - * Transaction since it may fail and time consuming. For example, - * URL request, disk IO, JDBC query, search query, HTTP request, 3rd party API - * call etc. - *

- * - *

- * Sometime if A needs call B which is owned by another team, although A and B - * are deployed together without any physical boundary. To make the ownership - * clear, there could be some Transaction logged when A calls B. - *

- * - *

- * Most of Transaction should be logged in the infrastructure level - * or framework level, which is transparent to the application. - *

- * - *

- * All CAT message will be constructed as a message tree and send to back-end - * for further analysis, and for monitoring. Only Transaction can - * be a tree node, all other message will be the tree leaf. The transaction - * without other messages nested is an atomic transaction. - *

- * - * @author Frankie Wu - */ - - public interface ITransaction : IMessage - { - /** - * Get all children message within current transaction. - * - *

- * Typically, a Transaction can nest other - * Transactions, Events and Heartbeat - * s, while an Event or Heartbeat can't nest other - * messages. - *

- * - * @return all children messages, empty if there is no nested children. - */ - IList Children { get; } - - /** - * How long the transaction took from construction to complete. Time unit is - * microsecond. - * - * @return duration time in microsecond - */ - long DurationInMicros { get; set; } - - /** - * How long the transaction took from construction to complete. Time unit is - * millisecond. - * - * @return duration time in millisecond - */ - long DurationInMillis { get; set; } - - /** - * Check if the transaction is stand-alone or belongs to another one. - * - * @return true if it's an root transaction. - */ - bool Standalone { get; set; } - - /** - * Add one nested child message to current transaction. - * - * @param message - * to be added - */ - ITransaction AddChild(IMessage message); - - /** - * Has children or not. An atomic transaction does not have any children - * message. - * - * @return true if child exists, else false. - */ - bool HasChildren(); - } +using System.Collections.Generic; + +namespace Com.Dianping.Cat.Message +{ + /** + *

+ * Transaction is any interesting unit of work that takes time to + * complete and may fail. + *

+ * + *

+ * Basically, all data access across the boundary needs to be logged as a + * Transaction since it may fail and time consuming. For example, + * URL request, disk IO, JDBC query, search query, HTTP request, 3rd party API + * call etc. + *

+ * + *

+ * Sometime if A needs call B which is owned by another team, although A and B + * are deployed together without any physical boundary. To make the ownership + * clear, there could be some Transaction logged when A calls B. + *

+ * + *

+ * Most of Transaction should be logged in the infrastructure level + * or framework level, which is transparent to the application. + *

+ * + *

+ * All CAT message will be constructed as a message tree and send to back-end + * for further analysis, and for monitoring. Only Transaction can + * be a tree node, all other message will be the tree leaf. The transaction + * without other messages nested is an atomic transaction. + *

+ * + * @author Frankie Wu + */ + + public interface ITransaction : IMessage + { + /** + * Get all children message within current transaction. + * + *

+ * Typically, a Transaction can nest other + * Transactions, Events and Heartbeat + * s, while an Event or Heartbeat can't nest other + * messages. + *

+ * + * @return all children messages, empty if there is no nested children. + */ + IList Children { get; } + + /** + * How long the transaction took from construction to complete. Time unit is + * microsecond. + * + * @return duration time in microsecond + */ + long DurationInMicros { get; set; } + + /** + * How long the transaction took from construction to complete. Time unit is + * millisecond. + * + * @return duration time in millisecond + */ + long DurationInMillis { get; set; } + + /** + * Check if the transaction is stand-alone or belongs to another one. + * + * @return true if it's an root transaction. + */ + bool Standalone { get; set; } + + /** + * Add one nested child message to current transaction. + * + * @param message + * to be added + */ + ITransaction AddChild(IMessage message); + + /** + * Has children or not. An atomic transaction does not have any children + * message. + * + * @return true if child exists, else false. + */ + bool HasChildren(); + } } \ No newline at end of file diff --git a/Message/Internals/AbstractMessage.cs b/Message/Internals/AbstractMessage.cs index 5d5345a..ba15fa2 100644 --- a/Message/Internals/AbstractMessage.cs +++ b/Message/Internals/AbstractMessage.cs @@ -1,126 +1,127 @@ -using System; -using System.Text; -using Com.Dianping.Cat.Message.Spi.Codec; -using Com.Dianping.Cat.Util; - -namespace Com.Dianping.Cat.Message.Internals -{ - public abstract class AbstractMessage : IMessage - { - private readonly String _mName; - private readonly String _mType; - private bool _mCompleted; - private StringBuilder _mData; - - private String _mStatus = "unset"; - - protected AbstractMessage(String type, String name) - { - _mType = type; - _mName = name; - TimestampInMicros = MilliSecondTimer.CurrentTimeMicros(); - } - - /// - /// 其实是Ticks除以10 - /// - protected long TimestampInMicros { get; private set; } - - #region IMessage Members - - public String Data - { - get { return _mData == null ? "" : _mData.ToString(); } - } - - public String Name - { - get { return _mName; } - } - - public String Status - { - get { return _mStatus; } - - set { _mStatus = value; } - } - - /// - /// 其实是Ticks除以10000 - /// - public long Timestamp - { - get { return TimestampInMicros/1000L; } - set { TimestampInMicros = value*1000L; } - } - - public String Type - { - get { return _mType; } - } - - public void AddData(String keyValuePairs) - { - if (_mData == null) - { - _mData = new StringBuilder(keyValuePairs); - } - else - { - _mData.Append(keyValuePairs); - } - } - - public void AddData(String key, Object value) - { - if (_mData == null) - { - _mData = new StringBuilder(); - } - else if (_mData.Length > 0) - { - _mData.Append('&'); - } - - _mData.Append(key).Append('=').Append(value); - } - - public virtual void Complete() - { - SetCompleted(true); - } - - public bool IsCompleted() - { - return _mCompleted; - } - - public bool IsSuccess() - { - return "0".Equals(_mStatus); - } - - public void SetStatus(Exception e) - { - _mStatus = e.GetType().FullName; - } - - #endregion - - protected void SetCompleted(bool completed) - { - _mCompleted = completed; - } - - public override String ToString() - { - PlainTextMessageCodec codec = new PlainTextMessageCodec(); - ChannelBuffer buf = new ChannelBuffer(8192); - - codec.EncodeMessage(this, buf); - buf.Reset(); - - return buf.ToString(); - } - } +using System; +using System.Text; +using Com.Dianping.Cat.Message.Spi.Codec; +using Com.Dianping.Cat.Util; + +namespace Com.Dianping.Cat.Message.Internals +{ + [Serializable] + public abstract class AbstractMessage : IMessage + { + private readonly String _mName; + private readonly String _mType; + private bool _mCompleted; + private StringBuilder _mData; + + private String _mStatus = "unset"; + + protected AbstractMessage(String type, String name) + { + _mType = type; + _mName = name; + TimestampInMicros = MilliSecondTimer.CurrentTimeMicros(); + } + + /// + /// 其实是Ticks除以10 + /// + protected long TimestampInMicros { get; private set; } + + #region IMessage Members + + public String Data + { + get { return _mData == null || _mData.Length == 0 ? string.Empty : _mData.ToString(); } + } + + public String Name + { + get { return _mName; } + } + + public String Status + { + get { return _mStatus; } + + set { _mStatus = value; } + } + + /// + /// 其实是Ticks除以10000 + /// + public long Timestamp + { + get { return TimestampInMicros / 1000L; } + set { TimestampInMicros = value * 1000L; } + } + + public String Type + { + get { return _mType; } + } + + public void AddData(String keyValuePairs) + { + if (_mData == null) + { + _mData = new StringBuilder(keyValuePairs); + } + else + { + _mData.Append(keyValuePairs); + } + } + + public void AddData(String key, Object value) + { + if (_mData == null) + { + _mData = new StringBuilder(); + } + else if (_mData.Length > 0) + { + _mData.Append('&'); + } + + _mData.Append(key).Append('=').Append(value); + } + + public virtual void Complete() + { + SetCompleted(true); + } + + public bool IsCompleted() + { + return _mCompleted; + } + + public bool IsSuccess() + { + return "0".Equals(_mStatus); + } + + public void SetStatus(Exception e) + { + _mStatus = e.GetType().FullName; + } + + #endregion + + protected void SetCompleted(bool completed) + { + _mCompleted = completed; + } + + public override String ToString() + { + PlainTextMessageCodec codec = new PlainTextMessageCodec(); + ChannelBuffer buf = new ChannelBuffer(8192); + + codec.EncodeMessage(this, buf); + buf.Reset(); + + return buf.ToString(); + } + } } \ No newline at end of file diff --git a/Message/Internals/DefaultEvent.cs b/Message/Internals/DefaultEvent.cs index 450cf8d..3336aae 100644 --- a/Message/Internals/DefaultEvent.cs +++ b/Message/Internals/DefaultEvent.cs @@ -1,11 +1,12 @@ -using System; - -namespace Com.Dianping.Cat.Message.Internals -{ - public class DefaultEvent : AbstractMessage, IEvent - { - public DefaultEvent(String type, String name) : base(type, name) - { - } - } +using System; + +namespace Com.Dianping.Cat.Message.Internals +{ + public class DefaultEvent : AbstractMessage, IEvent + { + public DefaultEvent(String type, String name) + : base(type, name) + { + } + } } \ No newline at end of file diff --git a/Message/Internals/DefaultHeartbeat.cs b/Message/Internals/DefaultHeartbeat.cs index 9725603..cffe0fe 100644 --- a/Message/Internals/DefaultHeartbeat.cs +++ b/Message/Internals/DefaultHeartbeat.cs @@ -1,11 +1,12 @@ -using System; - -namespace Com.Dianping.Cat.Message.Internals -{ - public class DefaultHeartbeat : AbstractMessage, IHeartbeat - { - public DefaultHeartbeat(String type, String name) : base(type, name) - { - } - } +using System; + +namespace Com.Dianping.Cat.Message.Internals +{ + public class DefaultHeartbeat : AbstractMessage, IHeartbeat + { + public DefaultHeartbeat(String type, String name) + : base(type, name) + { + } + } } \ No newline at end of file diff --git a/Message/Internals/DefaultMessageTree.cs b/Message/Internals/DefaultMessageTree.cs index 047ea7c..b75a433 100644 --- a/Message/Internals/DefaultMessageTree.cs +++ b/Message/Internals/DefaultMessageTree.cs @@ -1,102 +1,102 @@ -using Com.Dianping.Cat.Message.Spi.Codec; -using System; - -namespace Com.Dianping.Cat.Message.Internals -{ - public class DefaultMessageTree : IMessageTree - { - private String _mMessageId; - - private String _mParentMessageId; - - private String _mRootMessageId; - - #region IMessageTree Members - - public IMessageTree Copy() - { - DefaultMessageTree tree = new DefaultMessageTree(); - - tree.Domain = Domain; - tree.HostName = HostName; - tree.IpAddress = IpAddress; - tree.MessageId = _mMessageId; - tree.ParentMessageId = _mParentMessageId; - tree.RootMessageId = _mRootMessageId; - tree.SessionToken = SessionToken; - tree.ThreadGroupName = ThreadGroupName; - tree.ThreadId = ThreadId; - tree.ThreadName = ThreadName; - tree.Message = Message; - - return tree; - } - - public string Domain { get; set; } - - public string HostName { get; set; } - - public string IpAddress { get; set; } - - public IMessage Message { get; set; } - - public String MessageId - { - get { return _mMessageId; } - set - { - if (!string.IsNullOrEmpty(value)) - { - _mMessageId = value; - } - } - } - - public String ParentMessageId - { - get { return _mParentMessageId; } - set - { - if (!string.IsNullOrEmpty(value)) - { - _mParentMessageId = value; - } - } - } - - public String RootMessageId - { - get { return _mRootMessageId; } - set - { - if (!string.IsNullOrEmpty(value)) - { - _mRootMessageId = value; - } - } - } - - public string SessionToken { get; set; } - - public string ThreadGroupName { get; set; } - - public string ThreadId { get; set; } - - public string ThreadName { get; set; } - - #endregion - - public override String ToString() - { - PlainTextMessageCodec codec = new PlainTextMessageCodec(); - ChannelBuffer buf = new ChannelBuffer(8192); - - codec.Encode(this, buf); - - buf.Reset(); - buf.Skip(4); // get rid of length - - return buf.ToString(); - } - } +using Com.Dianping.Cat.Message.Spi.Codec; +using System; + +namespace Com.Dianping.Cat.Message.Internals +{ + public class DefaultMessageTree : IMessageTree + { + private String _mMessageId; + + private String _mParentMessageId; + + private String _mRootMessageId; + + #region IMessageTree Members + + public IMessageTree Copy() + { + DefaultMessageTree tree = new DefaultMessageTree(); + + tree.Domain = Domain; + tree.HostName = HostName; + tree.IpAddress = IpAddress; + tree.MessageId = _mMessageId; + tree.ParentMessageId = _mParentMessageId; + tree.RootMessageId = _mRootMessageId; + tree.SessionToken = SessionToken; + tree.ThreadGroupName = ThreadGroupName; + tree.ThreadId = ThreadId; + tree.ThreadName = ThreadName; + tree.Message = Message; + + return tree; + } + + public string Domain { get; set; } + + public string HostName { get; set; } + + public string IpAddress { get; set; } + + public IMessage Message { get; set; } + + public String MessageId + { + get { return _mMessageId; } + set + { + if (!string.IsNullOrEmpty(value)) + { + _mMessageId = value; + } + } + } + + public String ParentMessageId + { + get { return _mParentMessageId; } + set + { + if (!string.IsNullOrEmpty(value)) + { + _mParentMessageId = value; + } + } + } + + public String RootMessageId + { + get { return _mRootMessageId; } + set + { + if (!string.IsNullOrEmpty(value)) + { + _mRootMessageId = value; + } + } + } + + public string SessionToken { get; set; } + + public string ThreadGroupName { get; set; } + + public string ThreadId { get; set; } + + public string ThreadName { get; set; } + + #endregion + + public override String ToString() + { + PlainTextMessageCodec codec = new PlainTextMessageCodec(); + ChannelBuffer buf = new ChannelBuffer(8192); + + codec.Encode(this, buf); + + buf.Reset(); + buf.Skip(4); // get rid of length + + return buf.ToString(); + } + } } \ No newline at end of file diff --git a/Message/Internals/DefaultMetric.cs b/Message/Internals/DefaultMetric.cs new file mode 100644 index 0000000..74ed63a --- /dev/null +++ b/Message/Internals/DefaultMetric.cs @@ -0,0 +1,12 @@ +using System; + +namespace Com.Dianping.Cat.Message.Internals +{ + public class DefaultMetric : AbstractMessage, IMetric + { + public DefaultMetric(String type, String name) + : base(type, name) + { + } + } +} diff --git a/Message/Internals/DefaultTransaction.cs b/Message/Internals/DefaultTransaction.cs index b71f4ed..d08d0c3 100644 --- a/Message/Internals/DefaultTransaction.cs +++ b/Message/Internals/DefaultTransaction.cs @@ -1,113 +1,116 @@ -using Com.Dianping.Cat.Util; -using System; -using System.Collections.Generic; - -namespace Com.Dianping.Cat.Message.Internals -{ - public class DefaultTransaction : AbstractMessage, ITransaction - { - private readonly Action _endCallBack; - private IList _mChildren; - private long _mDurationInMicro; // must be less than 0 - - public DefaultTransaction(String type, String name, Action endCallBack) - : base(type, name) - { - _mDurationInMicro = -1; - _endCallBack = endCallBack; - Standalone = true; - } - - #region ITransaction Members - - public IList Children - { - get { return _mChildren ?? (_mChildren = new List()); } - } - - public long DurationInMicros - { - get - { - if (_mDurationInMicro >= 0) - { - return _mDurationInMicro; - } - // if it's not completed explicitly - long duration = 0; - int len = (_mChildren == null) ? 0 : _mChildren.Count; - - if (len > 0) - { - if (_mChildren != null) - { - IMessage lastChild = _mChildren[len - 1]; - - if (lastChild is ITransaction) - { - ITransaction trx = lastChild as ITransaction; - - duration = trx.Timestamp*1000L + trx.DurationInMicros - TimestampInMicros; - } - else - { - duration = lastChild.Timestamp*1000L - TimestampInMicros; - } - } - } - - return duration; - } - set { _mDurationInMicro = value; } - } - - public long DurationInMillis - { - get { return DurationInMicros/1000L; } - set { _mDurationInMicro = value*1000L; } - } - - public bool Standalone { get; set; } - - public ITransaction AddChild(IMessage message) - { - if (_mChildren == null) - { - _mChildren = new List(); - } - - _mChildren.Add(message); - return this; - } - - public override void Complete() - { - if (IsCompleted()) - { - // complete() was called more than once - IMessage evt0 = new DefaultEvent("CAT", "BadInstrument") {Status = "TransactionAlreadyCompleted"}; - - evt0.Complete(); - AddChild(evt0); - } - else - { - _mDurationInMicro = MilliSecondTimer.CurrentTimeMicros() - TimestampInMicros; - - SetCompleted(true); - - if (_endCallBack != null) - { - _endCallBack(this); - } - } - } - - public bool HasChildren() - { - return _mChildren != null && _mChildren.Count > 0; - } - - #endregion - } +using Com.Dianping.Cat.Util; +//using Newtonsoft.Json; +using System; +using System.Collections.Generic; + +namespace Com.Dianping.Cat.Message.Internals +{ + [Serializable] + public class DefaultTransaction : AbstractMessage, ITransaction + { + private readonly Action _endCallBack; + private IList _mChildren; + private long _mDurationInMicro; // must be less than 0 + + public DefaultTransaction(String type, String name, Action endCallBack) + : base(type, name) + { + _mDurationInMicro = -1; + _endCallBack = endCallBack; + Standalone = true; + } + + #region ITransaction Members + + //[JsonConverter(typeof(List))] + public IList Children + { + get { return _mChildren ?? (_mChildren = new List()); } + } + + public long DurationInMicros + { + get + { + if (_mDurationInMicro >= 0) + { + return _mDurationInMicro; + } + // if it's not completed explicitly + long duration = 0; + int len = (_mChildren == null) ? 0 : _mChildren.Count; + + if (len > 0) + { + if (_mChildren != null) + { + IMessage lastChild = _mChildren[len - 1]; + + if (lastChild is ITransaction) + { + ITransaction trx = lastChild as ITransaction; + + duration = trx.Timestamp * 1000L + trx.DurationInMicros - TimestampInMicros; + } + else + { + duration = lastChild.Timestamp * 1000L - TimestampInMicros; + } + } + } + + return duration; + } + set { _mDurationInMicro = value; } + } + + public long DurationInMillis + { + get { return DurationInMicros / 1000L; } + set { _mDurationInMicro = value * 1000L; } + } + + public bool Standalone { get; set; } + + public ITransaction AddChild(IMessage message) + { + if (_mChildren == null) + { + _mChildren = new List(); + } + + _mChildren.Add(message); + return this; + } + + public override void Complete() + { + if (IsCompleted()) + { + // complete() was called more than once + IMessage evt0 = new DefaultEvent("CAT", "BadInstrument") { Status = "TransactionAlreadyCompleted" }; + + evt0.Complete(); + AddChild(evt0); + } + else + { + _mDurationInMicro = MilliSecondTimer.CurrentTimeMicros() - TimestampInMicros; + + SetCompleted(true); + + if (_endCallBack != null) + { + _endCallBack(this); + } + } + } + + public bool HasChildren() + { + return _mChildren != null && _mChildren.Count > 0; + } + + #endregion + } } \ No newline at end of file diff --git a/Message/Internals/MessageId.cs b/Message/Internals/MessageId.cs index e1a501b..9f263fe 100644 --- a/Message/Internals/MessageId.cs +++ b/Message/Internals/MessageId.cs @@ -1,102 +1,102 @@ -using System.Globalization; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Com.Dianping.Cat.Message.Internals -{ - [Obsolete] - public class MessageId - { - private readonly String _mDomain; - - private readonly int _mIndex; - - private readonly String _mIpAddressInHex; - - private readonly long _mTimestamp; - - internal MessageId(String domain, String ipAddressInHex, long timestamp, int index) - { - _mDomain = domain; - _mIpAddressInHex = ipAddressInHex; - _mTimestamp = timestamp; - _mIndex = index; - } - - public String Domain - { - get { return _mDomain; } - } - - public int Index - { - get { return _mIndex; } - } - - public String IpAddressInHex - { - get { return _mIpAddressInHex; } - } - - public long Timestamp - { - get { return _mTimestamp; } - } - - public static MessageId Parse(String messageId) - { - IList list = messageId.Split('-'); - int len = list.Count; - - if (len >= 4) - { - String ipAddressInHex = list[len - 3]; - long timestamp = (Int64.Parse(list[len - 2], NumberStyles.Integer)); - int index = Int32.Parse(list[len - 1]); - String domain; - - if (len > 4) - { - // allow domain contains '-' - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < len - 3; i++) - { - if (i > 0) - { - sb.Append('-'); - } - - sb.Append(list[i]); - } - - domain = sb.ToString(); - } - else - { - domain = list[0]; - } - - return new MessageId(domain, ipAddressInHex, timestamp, index); - } - - throw new Exception("Invalid message id format: " + messageId); - } - - public override String ToString() - { - StringBuilder sb = new StringBuilder(_mDomain.Length + 32); - - sb.Append(_mDomain); - sb.Append('-'); - sb.Append(_mIpAddressInHex); - sb.Append('-'); - sb.Append(_mTimestamp); - sb.Append('-'); - sb.Append(_mIndex); - - return sb.ToString(); - } - } +using System.Globalization; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Com.Dianping.Cat.Message.Internals +{ + [Obsolete] + public class MessageId + { + private readonly String _mDomain; + + private readonly int _mIndex; + + private readonly String _mIpAddressInHex; + + private readonly long _mTimestamp; + + internal MessageId(String domain, String ipAddressInHex, long timestamp, int index) + { + _mDomain = domain; + _mIpAddressInHex = ipAddressInHex; + _mTimestamp = timestamp; + _mIndex = index; + } + + public String Domain + { + get { return _mDomain; } + } + + public int Index + { + get { return _mIndex; } + } + + public String IpAddressInHex + { + get { return _mIpAddressInHex; } + } + + public long Timestamp + { + get { return _mTimestamp; } + } + + public static MessageId Parse(String messageId) + { + IList list = messageId.Split('-'); + int len = list.Count; + + if (len >= 4) + { + String ipAddressInHex = list[len - 3]; + long timestamp = (Int64.Parse(list[len - 2], NumberStyles.Integer)); + int index = Int32.Parse(list[len - 1]); + String domain; + + if (len > 4) + { + // allow domain contains '-' + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < len - 3; i++) + { + if (i > 0) + { + sb.Append('-'); + } + + sb.Append(list[i]); + } + + domain = sb.ToString(); + } + else + { + domain = list[0]; + } + + return new MessageId(domain, ipAddressInHex, timestamp, index); + } + + throw new Exception("Invalid message id format: " + messageId); + } + + public override String ToString() + { + StringBuilder sb = new StringBuilder(_mDomain.Length + 32); + + sb.Append(_mDomain); + sb.Append('-'); + sb.Append(_mIpAddressInHex); + sb.Append('-'); + sb.Append(_mTimestamp); + sb.Append('-'); + sb.Append(_mIndex); + + return sb.ToString(); + } + } } \ No newline at end of file diff --git a/Message/Internals/NullEvent.cs b/Message/Internals/NullEvent.cs index a37d544..a631d46 100644 --- a/Message/Internals/NullEvent.cs +++ b/Message/Internals/NullEvent.cs @@ -1,9 +1,10 @@ -namespace Com.Dianping.Cat.Message.Internals -{ - public class NullEvent : AbstractMessage, IEvent - { - public NullEvent() : base(null, null) - { - } - } +namespace Com.Dianping.Cat.Message.Internals +{ + public class NullEvent : AbstractMessage, IEvent + { + public NullEvent() + : base(null, null) + { + } + } } \ No newline at end of file diff --git a/Message/Internals/NullHeartbeat.cs b/Message/Internals/NullHeartbeat.cs index ea39e40..f273d14 100644 --- a/Message/Internals/NullHeartbeat.cs +++ b/Message/Internals/NullHeartbeat.cs @@ -1,9 +1,10 @@ -namespace Com.Dianping.Cat.Message.Internals -{ - public class NullHeartbeat : AbstractMessage, IHeartbeat - { - public NullHeartbeat() : base(null, null) - { - } - } +namespace Com.Dianping.Cat.Message.Internals +{ + public class NullHeartbeat : AbstractMessage, IHeartbeat + { + public NullHeartbeat() + : base(null, null) + { + } + } } \ No newline at end of file diff --git a/Message/Internals/NullMetric.cs b/Message/Internals/NullMetric.cs new file mode 100644 index 0000000..4d5bf52 --- /dev/null +++ b/Message/Internals/NullMetric.cs @@ -0,0 +1,11 @@ + +namespace Com.Dianping.Cat.Message.Internals +{ + public class NullMetric : AbstractMessage, IMetric + { + public NullMetric() + : base(null, null) + { + } + } +} diff --git a/Message/Internals/NullTransaction.cs b/Message/Internals/NullTransaction.cs index 920ce9e..aa73f89 100644 --- a/Message/Internals/NullTransaction.cs +++ b/Message/Internals/NullTransaction.cs @@ -1,65 +1,66 @@ -using System.Collections.Generic; - -namespace Com.Dianping.Cat.Message.Internals -{ - public class NullTransaction : AbstractMessage, ITransaction - { - private IList _mChildren; - - public NullTransaction() : base(null, null) - { - } - - #region ITransaction Members - - public IList Children - { - get { return _mChildren ?? (_mChildren = new List()); } - } - - public long DurationInMicros - { - get { return 0; } - set - { - //do nothing here - } - } - - public long DurationInMillis - { - get { return 0; } - set - { - //do nothing here - } - } - - public bool Standalone - { - get { return true; } - set - { - //do nothing here - } - } - - public ITransaction AddChild(IMessage message) - { - // do nothing here - return this; - } - - public override void Complete() - { - // do nothing here - } - - public bool HasChildren() - { - return false; - } - - #endregion - } +using System.Collections.Generic; + +namespace Com.Dianping.Cat.Message.Internals +{ + public class NullTransaction : AbstractMessage, ITransaction + { + private IList _mChildren; + + public NullTransaction() + : base(null, null) + { + } + + #region ITransaction Members + + public IList Children + { + get { return _mChildren ?? (_mChildren = new List()); } + } + + public long DurationInMicros + { + get { return 0; } + set + { + //do nothing here + } + } + + public long DurationInMillis + { + get { return 0; } + set + { + //do nothing here + } + } + + public bool Standalone + { + get { return true; } + set + { + //do nothing here + } + } + + public ITransaction AddChild(IMessage message) + { + // do nothing here + return this; + } + + public override void Complete() + { + // do nothing here + } + + public bool HasChildren() + { + return false; + } + + #endregion + } } \ No newline at end of file diff --git a/Message/Spi/Codec/ChannelBuffer.cs b/Message/Spi/Codec/ChannelBuffer.cs index 6e99b4d..408fcc3 100644 --- a/Message/Spi/Codec/ChannelBuffer.cs +++ b/Message/Spi/Codec/ChannelBuffer.cs @@ -1,142 +1,142 @@ -using System.Text; -using System.IO; - -namespace Com.Dianping.Cat.Message.Spi.Codec -{ - public class ChannelBuffer - { - private readonly MemoryStream _mBuf; - - private readonly BinaryWriter _mWriter; - - public ChannelBuffer(int capacity) - { - _mBuf = new MemoryStream(capacity); - _mWriter = new BinaryWriter(_mBuf, Encoding.UTF8); - } - - /// - /// 从当前位置到目标字符第一次出现的位置有多少字节? - /// - /// - /// - public int BytesBefore(byte separator) - { - int count = 0; - long oldPosition = _mBuf.Position; - - while (_mBuf.Position < _mBuf.Length) - { - int b = _mBuf.ReadByte(); - - if (b == -1) - { - return -1; - } - if ((byte) b == separator) - { - _mBuf.Position = oldPosition; - return count; - } - - count++; - } - - _mBuf.Position = oldPosition; - return 0; - } - - public void Skip(int bytes) - { - _mBuf.Position += bytes; - } - - public int ReadableBytes() - { - return (int) (_mBuf.Length - _mBuf.Position); - } - - public int ReadBytes(byte[] data) - { - return _mBuf.Read(data, 0, data.Length); - } - - public byte ReadByte() - { - return (byte) (_mBuf.ReadByte() & 0xFF); - } - - public void WriteByte(byte b) - { - _mWriter.Write(b); - } - - public void WriteByte(char c) - { - _mWriter.Write((byte) (c & 0xFF)); - } - - public void WriteInt(int i) - { - _mWriter.Write(ToBytes(i)); - } - - public void WriteBytes(byte[] data) - { - _mWriter.Write(data); - } - - public void WriteBytes(byte[] data, int offset, int len) - { - _mWriter.Write(data, offset, len); - } - - // for test purpose - public void Reset() - { - _mBuf.Seek(0, SeekOrigin.Begin); - } - - /// - /// 在流的相应位置插入一个整数的字节(覆盖?) - /// - /// - /// - public void SetInt(int index, int i) - { - _mWriter.Seek(index, SeekOrigin.Begin); - _mWriter.Write(ToBytes(i)); - } - - private static byte[] ToBytes(int value) - { - byte[] bytes = new byte[4]; - - bytes[3] = (byte) value; - bytes[2] = (byte) (value >> 8); - bytes[1] = (byte) (value >> 16); - bytes[0] = (byte) (value >> 24); - return bytes; - } - - public byte[] ToArray() - { - return _mBuf.ToArray(); - } - - /// - /// 从当前位置到结尾的字节数组的字符串表示 - /// - /// - public override string ToString() - { - byte[] data = _mBuf.ToArray(); - int offset = (int) _mBuf.Position; - string str = Encoding.UTF8.GetString(data, offset, data.Length - offset); - - //ToArray本身就不为该Position,所以下一行代码多余 - //_mBuf.Seek(offset, SeekOrigin.Begin); - return str; - } - } +using System.Text; +using System.IO; + +namespace Com.Dianping.Cat.Message.Spi.Codec +{ + public class ChannelBuffer + { + private readonly MemoryStream _mBuf; + + private readonly BinaryWriter _mWriter; + + public ChannelBuffer(int capacity) + { + _mBuf = new MemoryStream(capacity); + _mWriter = new BinaryWriter(_mBuf, Encoding.UTF8); + } + + /// + /// 从当前位置到目标字符第一次出现的位置有多少字节? + /// + /// + /// + public int BytesBefore(byte separator) + { + int count = 0; + long oldPosition = _mBuf.Position; + + while (_mBuf.Position < _mBuf.Length) + { + int b = _mBuf.ReadByte(); + + if (b == -1) + { + return -1; + } + if ((byte)b == separator) + { + _mBuf.Position = oldPosition; + return count; + } + + count++; + } + + _mBuf.Position = oldPosition; + return 0; + } + + public void Skip(int bytes) + { + _mBuf.Position += bytes; + } + + public int ReadableBytes() + { + return (int)(_mBuf.Length - _mBuf.Position); + } + + public int ReadBytes(byte[] data) + { + return _mBuf.Read(data, 0, data.Length); + } + + public byte ReadByte() + { + return (byte)(_mBuf.ReadByte() & 0xFF); + } + + public void WriteByte(byte b) + { + _mWriter.Write(b); + } + + public void WriteByte(char c) + { + _mWriter.Write((byte)(c & 0xFF)); + } + + public void WriteInt(int i) + { + _mWriter.Write(ToBytes(i)); + } + + public void WriteBytes(byte[] data) + { + _mWriter.Write(data); + } + + public void WriteBytes(byte[] data, int offset, int len) + { + _mWriter.Write(data, offset, len); + } + + // for test purpose + public void Reset() + { + _mBuf.Seek(0, SeekOrigin.Begin); + } + + /// + /// 在流的相应位置插入一个整数的字节(覆盖?) + /// + /// + /// + public void SetInt(int index, int i) + { + _mWriter.Seek(index, SeekOrigin.Begin); + _mWriter.Write(ToBytes(i)); + } + + private static byte[] ToBytes(int value) + { + byte[] bytes = new byte[4]; + + bytes[3] = (byte)value; + bytes[2] = (byte)(value >> 8); + bytes[1] = (byte)(value >> 16); + bytes[0] = (byte)(value >> 24); + return bytes; + } + + public byte[] ToArray() + { + return _mBuf.ToArray(); + } + + /// + /// 从当前位置到结尾的字节数组的字符串表示 + /// + /// + public override string ToString() + { + byte[] data = _mBuf.ToArray(); + int offset = (int)_mBuf.Position; + string str = Encoding.UTF8.GetString(data, offset, data.Length - offset); + + //ToArray本身就不为该Position,所以下一行代码多余 + //_mBuf.Seek(offset, SeekOrigin.Begin); + return str; + } + } } \ No newline at end of file diff --git a/Message/Spi/Codec/IMessageCodec.cs b/Message/Spi/Codec/IMessageCodec.cs index 64daa0b..f738695 100644 --- a/Message/Spi/Codec/IMessageCodec.cs +++ b/Message/Spi/Codec/IMessageCodec.cs @@ -1,11 +1,11 @@ -namespace Com.Dianping.Cat.Message.Spi.Codec -{ - public interface IMessageCodec - { - IMessageTree Decode(ChannelBuffer buf); - - void Decode(ChannelBuffer buf, IMessageTree tree); - - void Encode(IMessageTree tree, ChannelBuffer buf); - } +namespace Com.Dianping.Cat.Message.Spi.Codec +{ + public interface IMessageCodec + { + IMessageTree Decode(ChannelBuffer buf); + + void Decode(ChannelBuffer buf, IMessageTree tree); + + void Encode(IMessageTree tree, ChannelBuffer buf); + } } \ No newline at end of file diff --git a/Message/Spi/Codec/PlainTextMessageCodec.cs b/Message/Spi/Codec/PlainTextMessageCodec.cs index e9fc980..bfc40d7 100644 --- a/Message/Spi/Codec/PlainTextMessageCodec.cs +++ b/Message/Spi/Codec/PlainTextMessageCodec.cs @@ -1,526 +1,539 @@ -using Com.Dianping.Cat.Message.Internals; -using Com.Dianping.Cat.Util; -using System; -using System.Text; -using System.Globalization; -using System.Collections.Generic; - -namespace Com.Dianping.Cat.Message.Spi.Codec -{ - public class PlainTextMessageCodec : IMessageCodec - { - #region Policy enum - - public enum Policy - { - DEFAULT, - - WITHOUT_STATUS, - - WITH_DURATION - } - - #endregion - - private const String ID = "PT1"; // plain text version 1 - - private const byte TAB = (byte) '\t'; // tab character - - private const byte LF = (byte) '\n'; // line feed character - - private readonly BufferHelper _mBufferHelper; - - private readonly DateHelper _mDateHelper; - - public PlainTextMessageCodec() - { - _mBufferHelper = new BufferHelper(); - _mDateHelper = new DateHelper(); - } - - #region IMessageCodec Members - - public virtual IMessageTree Decode(ChannelBuffer buf) - { - DefaultMessageTree tree = new DefaultMessageTree(); - - Decode(buf, tree); - return tree; - } - - public virtual void Decode(ChannelBuffer buf, IMessageTree tree) - { - DecodeHeader(buf, tree); - - if (buf.ReadableBytes() > 0) - { - DecodeMessage(buf, tree); - } - } - - public virtual void Encode(IMessageTree tree, ChannelBuffer buf) - { - int count = 0; - - buf.WriteInt(0); // place-holder - count += EncodeHeader(tree, buf); - - if (tree.Message != null) - { - count += EncodeMessage(tree.Message, buf); - } - - buf.SetInt(0, count); - } - - #endregion - - protected internal void DecodeHeader(ChannelBuffer buf, IMessageTree tree) - { - BufferHelper helper = _mBufferHelper; - String id = helper.Read(buf, TAB); - String domain = helper.Read(buf, TAB); - String hostName = helper.Read(buf, TAB); - String ipAddress = helper.Read(buf, TAB); - String threadGroupName = helper.Read(buf, TAB); - String threadId = helper.Read(buf, TAB); - String threadName = helper.Read(buf, TAB); - String messageId = helper.Read(buf, TAB); - String parentMessageId = helper.Read(buf, TAB); - String rootMessageId = helper.Read(buf, TAB); - String sessionToken = helper.Read(buf, LF); - - if (ID.Equals(id)) - { - tree.Domain = domain; - tree.HostName = hostName; - tree.IpAddress = ipAddress; - tree.ThreadGroupName = threadGroupName; - tree.ThreadId = threadId; - tree.ThreadName = threadName; - tree.MessageId = messageId; - tree.ParentMessageId = parentMessageId; - tree.RootMessageId = rootMessageId; - tree.SessionToken = sessionToken; - } - else - { - throw new Exception("Unrecognized id(" + id + ") for plain text message codec!"); - } - } - - protected internal IMessage DecodeLine(ChannelBuffer buf, ITransaction parent, - Stack stack, IMessageTree tree) - { - BufferHelper helper = _mBufferHelper; - byte identifier = buf.ReadByte(); - String timestamp = helper.Read(buf, TAB); - String type = helper.Read(buf, TAB); - String name = helper.Read(buf, TAB); - - if (identifier == 'E') - { - IMessage evt = new DefaultEvent(type, name); - String status = helper.Read(buf, TAB); - String data = helper.ReadRaw(buf, TAB); - - helper.Read(buf, LF); // get rid of line feed - evt.Timestamp = _mDateHelper.Parse(timestamp); - evt.Status = status; - evt.AddData(data); - - if (parent != null) - { - parent.AddChild(evt); - return parent; - } - return evt; - } - if (identifier == 'H') - { - IMessage heartbeat = new DefaultHeartbeat(type, name); - String status0 = helper.Read(buf, TAB); - String data1 = helper.ReadRaw(buf, TAB); - - helper.Read(buf, LF); // get rid of line feed - heartbeat.Timestamp = _mDateHelper.Parse(timestamp); - heartbeat.Status = status0; - heartbeat.AddData(data1); - - if (parent != null) - { - parent.AddChild(heartbeat); - return parent; - } - return heartbeat; - } - if (identifier == 't') - { - IMessage transaction = new DefaultTransaction(type, name, - null); - - helper.Read(buf, LF); // get rid of line feed - transaction.Timestamp = _mDateHelper.Parse(timestamp); - - if (parent != null) - { - parent.AddChild(transaction); - } - - stack.Push(parent); - return transaction; - } - if (identifier == 'A') - { - ITransaction transaction2 = new DefaultTransaction(type, name, null); - String status3 = helper.Read(buf, TAB); - String duration = helper.Read(buf, TAB); - String data4 = helper.ReadRaw(buf, TAB); - - helper.Read(buf, LF); // get rid of line feed - transaction2.Timestamp = _mDateHelper.Parse(timestamp); - transaction2.Status = status3; - transaction2.AddData(data4); - - long d = Int64.Parse(duration.Substring(0, duration.Length - 2), NumberStyles.Integer); - transaction2.DurationInMicros = d; - - if (parent != null) - { - parent.AddChild(transaction2); - return parent; - } - return transaction2; - } - if (identifier == 'T') - { - String status5 = helper.Read(buf, TAB); - String duration6 = helper.Read(buf, TAB); - String data7 = helper.ReadRaw(buf, TAB); - - helper.Read(buf, LF); // get rid of line feed - parent.Status = status5; - parent.AddData(data7); - - long d8 = Int64.Parse( - duration6.Substring(0, duration6.Length - 2), - NumberStyles.Integer); - parent.DurationInMicros = d8; - - return stack.Pop(); - } - Logger.Error("Unknown identifier(" + identifier + ") of message: " + buf); - - // unknown message, ignore it - return parent; - } - - protected internal void DecodeMessage(ChannelBuffer buf, IMessageTree tree) - { - Stack stack = new Stack(); - IMessage parent = DecodeLine(buf, null, stack, tree); - - tree.Message = parent; - - while (buf.ReadableBytes() > 0) - { - IMessage message = DecodeLine(buf, (ITransaction) parent, stack, tree); - - if (message is ITransaction) - { - parent = message; - } - else - { - break; - } - } - } - - protected internal int EncodeHeader(IMessageTree tree, ChannelBuffer buf) - { - BufferHelper helper = _mBufferHelper; - int count = 0; - - count += helper.Write(buf, ID); - count += helper.Write(buf, TAB); - count += helper.Write(buf, tree.Domain); - count += helper.Write(buf, TAB); - count += helper.Write(buf, tree.HostName); - count += helper.Write(buf, TAB); - count += helper.Write(buf, tree.IpAddress); - count += helper.Write(buf, TAB); - count += helper.Write(buf, tree.ThreadGroupName); - count += helper.Write(buf, TAB); - count += helper.Write(buf, tree.ThreadId); - count += helper.Write(buf, TAB); - count += helper.Write(buf, tree.ThreadName); - count += helper.Write(buf, TAB); - count += helper.Write(buf, tree.MessageId); - count += helper.Write(buf, TAB); - count += helper.Write(buf, tree.ParentMessageId); - count += helper.Write(buf, TAB); - count += helper.Write(buf, tree.RootMessageId); - count += helper.Write(buf, TAB); - count += helper.Write(buf, tree.SessionToken); - count += helper.Write(buf, LF); - - return count; - } - - protected internal int EncodeLine(IMessage message, ChannelBuffer buf, char type, Policy policy) - { - BufferHelper helper = _mBufferHelper; - int count = 0; - - count += helper.Write(buf, (byte) type); - - if (type == 'T' && message is ITransaction) - { - long duration = ((ITransaction) message).DurationInMillis; - - count += helper.Write(buf, _mDateHelper.Format(message.Timestamp + duration)); - } - else - { - count += helper.Write(buf, _mDateHelper.Format(message.Timestamp)); - } - - count += helper.Write(buf, TAB); - count += helper.Write(buf, message.Type); - count += helper.Write(buf, TAB); - count += helper.Write(buf, message.Name); - count += helper.Write(buf, TAB); - - if (policy != Policy.WITHOUT_STATUS) - { - count += helper.Write(buf, message.Status); - count += helper.Write(buf, TAB); - - Object data = message.Data; - - if (policy == Policy.WITH_DURATION && message is ITransaction) - { - long duration0 = ((ITransaction) message).DurationInMicros; - - count += helper.Write(buf, duration0.ToString(CultureInfo.InvariantCulture)); - //以微秒为单位 - count += helper.Write(buf, "us"); - count += helper.Write(buf, TAB); - } - - count += helper.WriteRaw(buf, data.ToString()); - count += helper.Write(buf, TAB); - } - - count += helper.Write(buf, LF); - - return count; - } - - public int EncodeMessage(IMessage message, ChannelBuffer buf) - { - if (message is IEvent) - { - return EncodeLine(message, buf, 'E', Policy.DEFAULT); - } - var transaction = message as ITransaction; - if (transaction != null) - { - IList children = transaction.Children; - - if ((children.Count == 0)) - { - return EncodeLine(transaction, buf, 'A', Policy.WITH_DURATION); - } - int count = 0; - int len = children.Count; - - count += EncodeLine(transaction, buf, 't', Policy.WITHOUT_STATUS); - - for (int i = 0; i < len; i++) - { - IMessage child = children[i]; - - count += EncodeMessage(child, buf); - } - - count += EncodeLine(transaction, buf, 'T', Policy.WITH_DURATION); - - return count; - } - if (message is IHeartbeat) - { - return EncodeLine(message, buf, 'H', Policy.DEFAULT); - } - throw new Exception("Unsupported message type: " + message.Type + "."); - } - - #region Nested type: BufferHelper - - protected internal class BufferHelper - { - private readonly UTF8Encoding _mEncoding = new UTF8Encoding(); - - public String Read(ChannelBuffer buf, byte separator) - { - int count = buf.BytesBefore(separator); - - if (count < 0) - { - return null; - } - byte[] data = new byte[count]; - - buf.ReadBytes(data); - buf.ReadByte(); // get rid of separator - - return Encoding.UTF8.GetString(data); - } - - public String ReadRaw(ChannelBuffer buf, byte separator) - { - int count = buf.BytesBefore(separator); - - if (count < 0) - { - return null; - } - byte[] data = new byte[count]; - - buf.ReadBytes(data); - buf.ReadByte(); // get rid of separator - - int length = data.Length; - - for (int i = 0; i < length; i++) - { - if (data[i] == '\\') - { - if (i + 1 < length) - { - byte b = data[i + 1]; - - if (b == 't') - { - data[i] = (byte) '\t'; - } - else if (b == 'r') - { - data[i] = (byte) '\r'; - } - else if (b == 'n') - { - data[i] = (byte) '\n'; - } - else - { - data[i] = b; - } - - Array.Copy(data, i + 2, data, i + 1, length - i - 2); - length--; - } - } - } - - return Encoding.UTF8.GetString(data, 0, length); - } - - public int Write(ChannelBuffer buf, byte b) - { - buf.WriteByte(b); - return 1; - } - - public int Write(ChannelBuffer buf, String str) - { - if (str == null) - { - str = "null"; - } - - byte[] data = _mEncoding.GetBytes(str); - - buf.WriteBytes(data); - return data.Length; - } - - public int WriteRaw(ChannelBuffer buf, String str) - { - if (str == null) - { - str = "null"; - } - - byte[] data = _mEncoding.GetBytes(str); - - int len = data.Length; - int count = len; - int offset = 0; - - for (int i = 0; i < len; i++) - { - byte b = data[i]; - - if (b == '\t' || b == '\r' || b == '\n' || b == '\\') - { - buf.WriteBytes(data, offset, i - offset); - buf.WriteByte('\\'); - - if (b == '\t') - { - buf.WriteByte('t'); - } - else if (b == '\r') - { - buf.WriteByte('r'); - } - else if (b == '\n') - { - buf.WriteByte('n'); - } - else - { - buf.WriteByte(b); - } - - count++; - offset = i + 1; - } - } - - if (len > offset) - { - buf.WriteBytes(data, offset, len - offset); - } - - return count; - } - } - - #endregion - - #region Nested type: DateHelper - - /// - /// Thread safe date helper class. DateFormat is NOT thread safe. - /// - protected internal class DateHelper - { - public String Format(long timestamp) - { - return new DateTime(timestamp*10000L).ToString("yyyy-MM-dd HH:mm:ss.fff"); - } - - public long Parse(String str) - { - DateTime dateTime = DateTime.ParseExact(str, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.CurrentCulture); - - return dateTime.Ticks/10000L; - } - } - - #endregion - } +using Com.Dianping.Cat.Message.Internals; +using Com.Dianping.Cat.Util; +using System; +using System.Text; +using System.Globalization; +using System.Collections.Generic; + +namespace Com.Dianping.Cat.Message.Spi.Codec +{ + public class PlainTextMessageCodec : IMessageCodec + { + #region Policy enum + + public enum Policy + { + DEFAULT, + + WITHOUT_STATUS, + + WITH_DURATION + } + + #endregion + + private const String ID = "PT1"; // plain text version 1 + + private const byte TAB = (byte)'\t'; // tab character + + private const byte LF = (byte)'\n'; // line feed character + + private readonly BufferHelper _mBufferHelper; + + private readonly DateHelper _mDateHelper; + + public PlainTextMessageCodec() + { + _mBufferHelper = new BufferHelper(); + _mDateHelper = new DateHelper(); + } + + #region IMessageCodec Members + + public virtual IMessageTree Decode(ChannelBuffer buf) + { + DefaultMessageTree tree = new DefaultMessageTree(); + + Decode(buf, tree); + return tree; + } + + public virtual void Decode(ChannelBuffer buf, IMessageTree tree) + { + DecodeHeader(buf, tree); + + if (buf.ReadableBytes() > 0) + { + DecodeMessage(buf, tree); + } + } + + public virtual void Encode(IMessageTree tree, ChannelBuffer buf) + { + int count = 0; + + buf.WriteInt(0); // place-holder + count += EncodeHeader(tree, buf); + + if (tree.Message != null) + { + count += EncodeMessage(tree.Message, buf); + } + + buf.SetInt(0, count); + } + + #endregion + + protected internal void DecodeHeader(ChannelBuffer buf, IMessageTree tree) + { + BufferHelper helper = _mBufferHelper; + String id = helper.Read(buf, TAB); + String domain = helper.Read(buf, TAB); + String hostName = helper.Read(buf, TAB); + String ipAddress = helper.Read(buf, TAB); + String threadGroupName = helper.Read(buf, TAB); + String threadId = helper.Read(buf, TAB); + String threadName = helper.Read(buf, TAB); + String messageId = helper.Read(buf, TAB); + String parentMessageId = helper.Read(buf, TAB); + String rootMessageId = helper.Read(buf, TAB); + String sessionToken = helper.Read(buf, LF); + + if (ID.Equals(id)) + { + tree.Domain = domain; + tree.HostName = hostName; + tree.IpAddress = ipAddress; + tree.ThreadGroupName = threadGroupName; + tree.ThreadId = threadId; + tree.ThreadName = threadName; + tree.MessageId = messageId; + tree.ParentMessageId = parentMessageId; + tree.RootMessageId = rootMessageId; + tree.SessionToken = sessionToken; + } + else + { + throw new Exception("Unrecognized id(" + id + ") for plain text message codec!"); + } + } + + protected internal IMessage DecodeLine(ChannelBuffer buf, ITransaction parent, + Stack stack, IMessageTree tree) + { + BufferHelper helper = _mBufferHelper; + char identifier = (char)buf.ReadByte(); + String timestamp = helper.Read(buf, TAB); + String type = helper.Read(buf, TAB); + String name = helper.Read(buf, TAB); + switch (identifier) + { + case 't': + IMessage transaction = new DefaultTransaction(type, name, null); + + helper.Read(buf, LF); // get rid of line feed + transaction.Timestamp = _mDateHelper.Parse(timestamp); + + if (parent != null) + { + parent.AddChild(transaction); + } + + stack.Push(parent); + return transaction; + case 'A': + DefaultTransaction tran = new DefaultTransaction(type, name, null); + String status = helper.Read(buf, TAB); + String duration = helper.Read(buf, TAB); + String data = helper.ReadRaw(buf, TAB); + + helper.Read(buf, LF); // get rid of line feed + tran.Timestamp = _mDateHelper.Parse(timestamp); + tran.Status = status; + tran.AddData(data); + + long d = Int64.Parse(duration.Substring(0, duration.Length - 2), NumberStyles.Integer); + + tran.DurationInMicros = d; + + if (parent != null) + { + parent.AddChild(tran); + return parent; + } + return tran; + case 'T': + String transactionStatus = helper.Read(buf, TAB); + String transactionDuration = helper.Read(buf, TAB); + String transactionData = helper.ReadRaw(buf, TAB); + + helper.Read(buf, LF); // get rid of line feed + parent.Status = transactionStatus; + parent.AddData(transactionData); + + long transactionD = Int64.Parse(transactionDuration.Substring(0, transactionDuration.Length - 2), NumberStyles.Integer); + + parent.DurationInMicros = transactionD; + + return stack.Pop(); + case 'E': + DefaultEvent evt = new DefaultEvent(type, name); + String eventStatus = helper.Read(buf, TAB); + String eventData = helper.ReadRaw(buf, TAB); + + helper.Read(buf, LF); // get rid of line feed + evt.Timestamp = _mDateHelper.Parse(timestamp); + evt.Status = eventStatus; + evt.AddData(eventData); + + if (parent != null) + { + parent.AddChild(evt); + return parent; + } + return evt; + case 'M': + DefaultMetric metric = new DefaultMetric(type, name); + String metricStatus = helper.Read(buf, TAB); + String metricData = helper.ReadRaw(buf, TAB); + + helper.Read(buf, LF); + metric.Timestamp = _mDateHelper.Parse(timestamp); + metric.Status = metricStatus; + metric.AddData(metricData); + + if (parent != null) + { + parent.AddChild(metric); + return parent; + } + return metric; + case 'H': + DefaultHeartbeat heartbeat = new DefaultHeartbeat(type, name); + String heartbeatStatus = helper.Read(buf, TAB); + String heartbeatData = helper.ReadRaw(buf, TAB); + + helper.Read(buf, LF); // get rid of line feed + heartbeat.Timestamp = _mDateHelper.Parse(timestamp); + heartbeat.Status = heartbeatStatus; + heartbeat.AddData(heartbeatData); + + if (parent != null) + { + parent.AddChild(heartbeat); + return parent; + } + return heartbeat; + } + + Logger.Error("Unknown identifier(" + identifier + ") of message: " + buf); + //throw new Exception("Unknown identifier int name"); //java版的抛出异常 + + // unknown message, ignore it + return parent; + } + + protected internal void DecodeMessage(ChannelBuffer buf, IMessageTree tree) + { + Stack stack = new Stack(); + IMessage parent = DecodeLine(buf, null, stack, tree); + + tree.Message = parent; + + while (buf.ReadableBytes() > 0) + { + IMessage message = DecodeLine(buf, (ITransaction)parent, stack, tree); + + if (message is ITransaction) + { + parent = message; + } + else + { + break; + } + } + } + + protected internal int EncodeHeader(IMessageTree tree, ChannelBuffer buf) + { + BufferHelper helper = _mBufferHelper; + int count = 0; + + count += helper.Write(buf, ID); + count += helper.Write(buf, TAB); + count += helper.Write(buf, tree.Domain); + count += helper.Write(buf, TAB); + count += helper.Write(buf, tree.HostName); + count += helper.Write(buf, TAB); + count += helper.Write(buf, tree.IpAddress); + count += helper.Write(buf, TAB); + count += helper.Write(buf, tree.ThreadGroupName); + count += helper.Write(buf, TAB); + count += helper.Write(buf, tree.ThreadId); + count += helper.Write(buf, TAB); + count += helper.Write(buf, tree.ThreadName); + count += helper.Write(buf, TAB); + count += helper.Write(buf, tree.MessageId); + count += helper.Write(buf, TAB); + count += helper.Write(buf, tree.ParentMessageId); + count += helper.Write(buf, TAB); + count += helper.Write(buf, tree.RootMessageId); + count += helper.Write(buf, TAB); + count += helper.Write(buf, tree.SessionToken); + count += helper.Write(buf, LF); + + return count; + } + + protected internal int EncodeLine(IMessage message, ChannelBuffer buf, char type, Policy policy) + { + BufferHelper helper = _mBufferHelper; + int count = 0; + + count += helper.Write(buf, (byte)type); + + if (type == 'T' && message is ITransaction) + { + long duration = ((ITransaction)message).DurationInMillis; + + count += helper.Write(buf, _mDateHelper.Format(message.Timestamp + duration)); + } + else + { + count += helper.Write(buf, _mDateHelper.Format(message.Timestamp)); + } + + count += helper.Write(buf, TAB); + count += helper.Write(buf, message.Type); + count += helper.Write(buf, TAB); + count += helper.Write(buf, message.Name); + count += helper.Write(buf, TAB); + + if (policy != Policy.WITHOUT_STATUS) + { + count += helper.Write(buf, message.Status); + count += helper.Write(buf, TAB); + + Object data = message.Data; + + if (policy == Policy.WITH_DURATION && message is ITransaction) + { + long duration0 = ((ITransaction)message).DurationInMicros; + + count += helper.Write(buf, duration0.ToString(CultureInfo.InvariantCulture)); + //以微秒为单位 + count += helper.Write(buf, "us"); + count += helper.Write(buf, TAB); + } + + count += helper.WriteRaw(buf, data.ToString()); + count += helper.Write(buf, TAB); + } + + count += helper.Write(buf, LF); + + return count; + } + + public int EncodeMessage(IMessage message, ChannelBuffer buf) + { + if (message is ITransaction) + { + var transaction = message as ITransaction; + IList children = transaction.Children; + + if (children.Count == 0) + { + return EncodeLine(transaction, buf, 'A', Policy.WITH_DURATION); + } + int count = 0; + int len = children.Count; + + count += EncodeLine(transaction, buf, 't', Policy.WITHOUT_STATUS); + + for (int i = 0; i < len; i++) + { + IMessage child = children[i]; + + count += EncodeMessage(child, buf); + } + + count += EncodeLine(transaction, buf, 'T', Policy.WITH_DURATION); + + return count; + } + if (message is IEvent) + { + return EncodeLine(message, buf, 'E', Policy.DEFAULT); + } + if (message is IHeartbeat) + { + return EncodeLine(message, buf, 'H', Policy.DEFAULT); + } + if (message is IMetric) + { + return EncodeLine(message, buf, 'M', Policy.DEFAULT); + } + throw new Exception(string.Format("Unsupported message type: {0}.", message.Type)); + } + + #region Nested type: BufferHelper + + protected internal class BufferHelper + { + private readonly UTF8Encoding _mEncoding = new UTF8Encoding(); + + public String Read(ChannelBuffer buf, byte separator) + { + int count = buf.BytesBefore(separator); + + if (count < 0) + { + return null; + } + byte[] data = new byte[count]; + + buf.ReadBytes(data); + buf.ReadByte(); // get rid of separator + + return Encoding.UTF8.GetString(data); + } + + public String ReadRaw(ChannelBuffer buf, byte separator) + { + int count = buf.BytesBefore(separator); + + if (count < 0) + { + return null; + } + byte[] data = new byte[count]; + + buf.ReadBytes(data); + buf.ReadByte(); // get rid of separator + + int length = data.Length; + + for (int i = 0; i < length; i++) + { + if (data[i] == '\\') + { + if (i + 1 < length) + { + byte b = data[i + 1]; + + if (b == 't') + { + data[i] = (byte)'\t'; + } + else if (b == 'r') + { + data[i] = (byte)'\r'; + } + else if (b == 'n') + { + data[i] = (byte)'\n'; + } + else + { + data[i] = b; + } + + Array.Copy(data, i + 2, data, i + 1, length - i - 2); + length--; + } + } + } + + return Encoding.UTF8.GetString(data, 0, length); + } + + public int Write(ChannelBuffer buf, byte b) + { + buf.WriteByte(b); + return 1; + } + + public int Write(ChannelBuffer buf, String str) + { + if (str == null) + { + str = "null"; + } + + byte[] data = _mEncoding.GetBytes(str); + + buf.WriteBytes(data); + return data.Length; + } + + public int WriteRaw(ChannelBuffer buf, String str) + { + if (str == null) + { + str = "null"; + } + + byte[] data = _mEncoding.GetBytes(str); + + int len = data.Length; + int count = len; + int offset = 0; + + for (int i = 0; i < len; i++) + { + byte b = data[i]; + + if (b == '\t' || b == '\r' || b == '\n' || b == '\\') + { + buf.WriteBytes(data, offset, i - offset); + buf.WriteByte('\\'); + + if (b == '\t') + { + buf.WriteByte('t'); + } + else if (b == '\r') + { + buf.WriteByte('r'); + } + else if (b == '\n') + { + buf.WriteByte('n'); + } + else + { + buf.WriteByte(b); + } + + count++; + offset = i + 1; + } + } + + if (len > offset) + { + buf.WriteBytes(data, offset, len - offset); + } + + return count; + } + } + + #endregion + + #region Nested type: DateHelper + + /// + /// Thread safe date helper class. DateFormat is NOT thread safe. + /// + protected internal class DateHelper + { + public String Format(long timestamp) + { + return new DateTime(timestamp * 10000L).ToString("yyyy-MM-dd HH:mm:ss.fff"); + } + + public long Parse(String str) + { + DateTime dateTime = DateTime.ParseExact(str, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.CurrentCulture); + + return dateTime.Ticks / 10000L; + } + } + + #endregion + } } \ No newline at end of file diff --git a/Message/Spi/IMessageManager.cs b/Message/Spi/IMessageManager.cs index 4973ddb..3e39120 100644 --- a/Message/Spi/IMessageManager.cs +++ b/Message/Spi/IMessageManager.cs @@ -1,77 +1,80 @@ -using Com.Dianping.Cat.Configuration; - -namespace Com.Dianping.Cat.Message.Spi -{ - /// - /// Message manager to help build CAT message.

Notes: This method is reserved for internal usage only. Application developer - /// should never call this method directly.

- ///
- public interface IMessageManager - { - /// - /// Return configuration for CAT client. - /// - /// CAT configuration - ClientConfig ClientConfig { get; } - - //TransportManager TransportManager { get; } - - /// - /// Get peek transaction for current thread. - /// - /// peek transaction for current thread, null if no transaction there. - ITransaction PeekTransaction { get; } - - /// - /// Get thread local message information. - /// - /// message tree, null means current thread is not setup correctly. - IMessageTree ThreadLocalMessageTree { get; } - - /// - /// Check if CAT logging is enabled or disabled. - /// - /// true if CAT is enabled - bool CatEnabled { get; } - - /// - /// 用于添加Event或者Heartbeat到peek transaction或者到根 如果是添加到根,建议直接使用IMessageProducer中的LogError、LogEvent或LogHeartbeat方法 - /// - /// - void Add(IMessage message); - - /// - /// Initialize CAT client with given CAT configuration. - /// - /// CAT configuration - void InitializeClient(ClientConfig config); - - /// - /// Do cleanup for current thread environment in order to release resources in thread local objects. - /// - void Reset(); - - /// - /// Check if the thread context is setup or not. - /// - /// true if the thread context is setup, false otherwise - bool HasContext(); - - /// - /// Do setup for current thread environment in order to prepare thread local objects. - /// - void Setup(); - - /// - /// Be triggered when a new transaction starts, whatever it's the root transaction or nested transaction. - /// - /// - void Start(ITransaction transaction); - - /// - /// Be triggered when a transaction ends, whatever it's the root transaction or nested transaction. However, if it's the root transaction then it will be flushed to back-end CAT server asynchronously. - /// - /// - void End(ITransaction transaction); - } +using Com.Dianping.Cat.Configuration; +using Com.Dianping.Cat.Message.Spi.Internals; + +namespace Com.Dianping.Cat.Message.Spi +{ + /// + /// Message manager to help build CAT message.

Notes: This method is reserved for internal usage only. Application developer + /// should never call this method directly.

+ ///
+ public interface IMessageManager + { + /// + /// Return configuration for CAT client. + /// + /// CAT configuration + ClientConfig ClientConfig { get; } + + //TransportManager TransportManager { get; } + + /// + /// Get peek transaction for current thread. + /// + /// peek transaction for current thread, null if no transaction there. + ITransaction PeekTransaction { get; } + + /// + /// Get thread local message information. + /// + /// message tree, null means current thread is not setup correctly. + IMessageTree ThreadLocalMessageTree { get; } + + /// + /// Check if CAT logging is enabled or disabled. + /// + /// true if CAT is enabled + bool CatEnabled { get; } + + /// + /// 用于添加Event或者Heartbeat到peek transaction或者到根 如果是添加到根,建议直接使用IMessageProducer中的LogError、LogEvent或LogHeartbeat方法 + /// + /// + void Add(IMessage message); + + /// + /// Initialize CAT client with given CAT configuration. + /// + /// CAT configuration + void InitializeClient(ClientConfig config); + + /// + /// Do cleanup for current thread environment in order to release resources in thread local objects. + /// + void Reset(); + + /// + /// Check if the thread context is setup or not. + /// + /// true if the thread context is setup, false otherwise + bool HasContext(); + + /// + /// Do setup for current thread environment in order to prepare thread local objects. + /// + void Setup(); + + /// + /// Be triggered when a new transaction starts, whatever it's the root transaction or nested transaction. + /// + /// + void Start(ITransaction transaction); + + /// + /// Be triggered when a transaction ends, whatever it's the root transaction or nested transaction. However, if it's the root transaction then it will be flushed to back-end CAT server asynchronously. + /// + /// + void End(ITransaction transaction); + + MessageIdFactory GetMessageIdFactory(); + } } \ No newline at end of file diff --git a/Message/Spi/IMessageProducer.cs b/Message/Spi/IMessageProducer.cs index bdb51ea..655756c 100644 --- a/Message/Spi/IMessageProducer.cs +++ b/Message/Spi/IMessageProducer.cs @@ -1,131 +1,149 @@ -using System; - -namespace Com.Dianping.Cat.Message.Spi -{ - /// - ///

Message factory is used to create new transaction,event and/or heartbeat.

Normally, application code logs message in following ways, for example: - ///

    - ///
  • Event - ///
    public class MyClass { 
    -    ///                                                                                           public static MessageFactory CAT = Cat.getFactory();
    -    ///                                                                                           public void bizMethod() { 
    -    ///                                                                                           Event event = CAT.newEvent("Review", "New");
    -    ///                                                                                           event.addData("id", 12345); 
    -    ///                                                                                           event.addData("user", "john");
    -    ///                                                                                           ...
    -    ///                                                                                           event.setStatus("0"); 
    -    ///                                                                                           event.complete(); 
    -    ///                                                                                           }
    -    ///                                                                                           ...
    -    ///                                                                                           }
    - ///
  • - ///
  • Heartbeat - ///
    public class MyClass { 
    -    ///                                                                                           public static MessageFactory CAT = Cat.getFactory();
    -    ///                                                                                           public void bizMethod() { 
    -    ///                                                                                           Heartbeat event = CAT.newHeartbeat("System", "Status");
    -    ///                                                                                           event.addData("ip", "192.168.10.111");
    -    ///                                                                                           event.addData("host", "host-1");
    -    ///                                                                                           event.addData("load", "2.1");
    -    ///                                                                                           event.addData("cpu", "0.12,0.10");
    -    ///                                                                                           event.addData("memory.total", "2G");
    -    ///                                                                                           event.addData("memory.free", "456M");
    -    ///                                                                                           event.setStatus("0");
    -    ///                                                                                           event.complete();
    -    ///                                                                                           }
    -    ///                                                                                           ...
    -    ///                                                                                           }
    - ///
  • - ///
  • Transaction - ///
    public class MyClass { 
    -    ///                                                                                           public static MessageFactory CAT = Cat.getFactory();
    -    ///                                                                                           public void bizMethod() { 
    -    ///                                                                                           Transaction t = CAT.newTransaction("URL", "MyPage");
    -    ///                                                                                           try {
    -    ///                                                                                           // do your business here
    -    ///                                                                                           t.addData("k1", "v1");
    -    ///                                                                                           t.addData("k2", "v2");
    -    ///                                                                                           t.addData("k3", "v3");
    -    ///                                                                                           Thread.sleep(30);
    -    ///                                                                                           t.setStatus("0");
    -    ///                                                                                           } catch (Exception e) {
    -    ///                                                                                           t.setStatus(e);
    -    ///                                                                                           } finally {
    -    ///                                                                                           t.complete();
    -    ///                                                                                           }
    -    ///                                                                                           }
    -    ///                                                                                           ...
    -    ///                                                                                           }
    - ///
  • - ///
- /// or logs event or heartbeat in one shot, for example: - ///
    - ///
  • Event - ///
    public class MyClass { 
    -    ///                                                                                           public static MessageFactory CAT = Cat.getFactory();
    -    ///                                                                                           public void bizMethod() { 
    -    ///                                                                                           CAT.logEvent("Review", "New", "0", "id=12345&user=john");
    -    ///                                                                                           }
    -    ///                                                                                           ...
    -    ///                                                                                           }
    - ///
  • - ///
  • Heartbeat - ///
    public class MyClass { 
    -    ///                                                                                           public static MessageFactory CAT = Cat.getFactory();
    -    ///                                                                                           public void bizMethod() { 
    -    ///                                                                                           CAT.logHeartbeat("System", "Status", "0", "ip=192.168.10.111&host=host-1&load=2.1&cpu=0.12,0.10&memory.total=2G&memory.free=456M");
    -    ///                                                                                           }
    -    ///                                                                                           ...
    -    ///                                                                                           }
    - ///
  • - ///
- ///

- ///
- public interface IMessageProducer - { - /// - /// Log an error. - /// - /// root cause exception - void LogError(Exception cause); - - /// - /// Log an event in one shot. - /// - /// event type - /// event name - /// "0" means success, otherwise means error code - /// name value pairs in the format of "a=1&b=2&..." - void LogEvent(String type, String name, String status, String nameValuePairs); - - /// - /// Log a heartbeat in one shot. - /// - /// heartbeat type - /// heartbeat name - /// "0" means success, otherwise means error code - /// name value pairs in the format of "a=1&b=2&..." - void LogHeartbeat(String type, String name, String status, String nameValuePairs); - - /// - /// Create a new event with given type and name. - /// - /// event type - /// event name - IEvent NewEvent(String type, String name); - - /// - /// Create a new heartbeat with given type and name. - /// - /// heartbeat type - /// heartbeat name - IHeartbeat NewHeartbeat(String type, String name); - - /// - /// Create a new transaction with given type and name. - /// - /// transaction type - /// transaction name - ITransaction NewTransaction(String type, String name); - } +using System; + +namespace Com.Dianping.Cat.Message.Spi +{ + /// + ///

Message factory is used to create new transaction,event and/or heartbeat.

Normally, application code logs message in following ways, for example: + ///

    + ///
  • Event + ///
    public class MyClass { 
    +    ///                                                                                           public static MessageFactory CAT = Cat.getFactory();
    +    ///                                                                                           public void bizMethod() { 
    +    ///                                                                                           Event event = CAT.newEvent("Review", "New");
    +    ///                                                                                           event.addData("id", 12345); 
    +    ///                                                                                           event.addData("user", "john");
    +    ///                                                                                           ...
    +    ///                                                                                           event.setStatus("0"); 
    +    ///                                                                                           event.complete(); 
    +    ///                                                                                           }
    +    ///                                                                                           ...
    +    ///                                                                                           }
    + ///
  • + ///
  • Heartbeat + ///
    public class MyClass { 
    +    ///                                                                                           public static MessageFactory CAT = Cat.getFactory();
    +    ///                                                                                           public void bizMethod() { 
    +    ///                                                                                           Heartbeat event = CAT.newHeartbeat("System", "Status");
    +    ///                                                                                           event.addData("ip", "192.168.10.111");
    +    ///                                                                                           event.addData("host", "host-1");
    +    ///                                                                                           event.addData("load", "2.1");
    +    ///                                                                                           event.addData("cpu", "0.12,0.10");
    +    ///                                                                                           event.addData("memory.total", "2G");
    +    ///                                                                                           event.addData("memory.free", "456M");
    +    ///                                                                                           event.setStatus("0");
    +    ///                                                                                           event.complete();
    +    ///                                                                                           }
    +    ///                                                                                           ...
    +    ///                                                                                           }
    + ///
  • + ///
  • Transaction + ///
    public class MyClass { 
    +    ///                                                                                           public static MessageFactory CAT = Cat.getFactory();
    +    ///                                                                                           public void bizMethod() { 
    +    ///                                                                                           Transaction t = CAT.newTransaction("URL", "MyPage");
    +    ///                                                                                           try {
    +    ///                                                                                           // do your business here
    +    ///                                                                                           t.addData("k1", "v1");
    +    ///                                                                                           t.addData("k2", "v2");
    +    ///                                                                                           t.addData("k3", "v3");
    +    ///                                                                                           Thread.sleep(30);
    +    ///                                                                                           t.setStatus("0");
    +    ///                                                                                           } catch (Exception e) {
    +    ///                                                                                           t.setStatus(e);
    +    ///                                                                                           } finally {
    +    ///                                                                                           t.complete();
    +    ///                                                                                           }
    +    ///                                                                                           }
    +    ///                                                                                           ...
    +    ///                                                                                           }
    + ///
  • + ///
+ /// or logs event or heartbeat in one shot, for example: + ///
    + ///
  • Event + ///
    public class MyClass { 
    +    ///                                                                                           public static MessageFactory CAT = Cat.getFactory();
    +    ///                                                                                           public void bizMethod() { 
    +    ///                                                                                           CAT.logEvent("Review", "New", "0", "id=12345&user=john");
    +    ///                                                                                           }
    +    ///                                                                                           ...
    +    ///                                                                                           }
    + ///
  • + ///
  • Heartbeat + ///
    public class MyClass { 
    +    ///                                                                                           public static MessageFactory CAT = Cat.getFactory();
    +    ///                                                                                           public void bizMethod() { 
    +    ///                                                                                           CAT.logHeartbeat("System", "Status", "0", "ip=192.168.10.111&host=host-1&load=2.1&cpu=0.12,0.10&memory.total=2G&memory.free=456M");
    +    ///                                                                                           }
    +    ///                                                                                           ...
    +    ///                                                                                           }
    + ///
  • + ///
+ ///

+ ///
+ public interface IMessageProducer + { + String CreateMessageId(); + + /// + /// Log an error. + /// + /// root cause exception + void LogError(Exception cause); + + /// + /// Log an event in one shot. + /// + /// event type + /// event name + /// "0" means success, otherwise means error code + /// name value pairs in the format of "a=1&b=2&..." + void LogEvent(String type, String name, String status, String nameValuePairs); + + /// + /// Log a heartbeat in one shot. + /// + /// heartbeat type + /// heartbeat name + /// "0" means success, otherwise means error code + /// name value pairs in the format of "a=1&b=2&..." + void LogHeartbeat(String type, String name, String status, String nameValuePairs); + + /// + /// Log a metric in one shot. + /// + /// metric name + /// "0" means success, otherwise means error code + /// name value pairs in the format of "a=1&b=2&..." + void LogMetric(String name, String status, String nameValuePairs); + + /// + /// Create a new event with given type and name. + /// + /// event type + /// event name + IEvent NewEvent(String type, String name); + + /// + /// Create a new heartbeat with given type and name. + /// + /// heartbeat type + /// heartbeat name + IHeartbeat NewHeartbeat(String type, String name); + + /// + /// Create a new transaction with given type and name. + /// + /// transaction type + /// transaction name + ITransaction NewTransaction(String type, String name); + + /// + /// Create a new metric with given type and name. + /// + /// metric type + /// metric name + IMetric NewMetric(String type, String name); + + } } \ No newline at end of file diff --git a/Message/Spi/IMessageStatistics.cs b/Message/Spi/IMessageStatistics.cs index e289cf0..c3a3fb0 100644 --- a/Message/Spi/IMessageStatistics.cs +++ b/Message/Spi/IMessageStatistics.cs @@ -1,17 +1,17 @@ -namespace Com.Dianping.Cat.Message.Spi -{ - public interface IMessageStatistics - { - long Produced { get; set; } - - long Overflowed { get; set; } - - long Bytes { get; set; } - - void OnSending(IMessageTree tree); - - void OnOverflowed(IMessageTree tree); - - void OnBytes(int size); - } +namespace Com.Dianping.Cat.Message.Spi +{ + public interface IMessageStatistics + { + long Produced { get; set; } + + long Overflowed { get; set; } + + long Bytes { get; set; } + + void OnSending(IMessageTree tree); + + void OnOverflowed(IMessageTree tree); + + void OnBytes(int size); + } } \ No newline at end of file diff --git a/Message/Spi/IO/IMessageSender.cs b/Message/Spi/IO/IMessageSender.cs index 7d1c881..09d8f65 100644 --- a/Message/Spi/IO/IMessageSender.cs +++ b/Message/Spi/IO/IMessageSender.cs @@ -1,13 +1,13 @@ -namespace Com.Dianping.Cat.Message.Spi.IO -{ - public interface IMessageSender - { - bool HasSendingMessage { get; } - - void Initialize(); - - void Send(IMessageTree tree); - - void Shutdown(); - } +namespace Com.Dianping.Cat.Message.Spi.IO +{ + public interface IMessageSender + { + bool HasSendingMessage { get; } + + void Initialize(); + + void Send(IMessageTree tree); + + void Shutdown(); + } } \ No newline at end of file diff --git a/Message/Spi/IO/TcpMessageSender.cs b/Message/Spi/IO/TcpMessageSender.cs index 5ee4edc..a64efae 100644 --- a/Message/Spi/IO/TcpMessageSender.cs +++ b/Message/Spi/IO/TcpMessageSender.cs @@ -1,263 +1,263 @@ -using System; -using Com.Dianping.Cat.Configuration; -using Com.Dianping.Cat.Message.Spi.Codec; -using Com.Dianping.Cat.Util; -using System.Collections.Generic; -using System.Net.Sockets; -using System.Threading; - -namespace Com.Dianping.Cat.Message.Spi.IO -{ - public class TcpMessageSender : IMessageSender - { - private readonly ClientConfig _mClientConfig; - private readonly IMessageCodec _mCodec; - private readonly IList _mQueue; - private readonly IMessageStatistics _mStatistics; - private bool _mActive; - private TcpClient _mActiveChannel; - private int _mActiveIndex; - private int _mErrors; - private TcpClient _mLastChannel; - - public TcpMessageSender(ClientConfig clientConfig, IMessageStatistics statistics) - { - _mClientConfig = clientConfig; - _mStatistics = statistics; - _mActive = true; - _mQueue = new List(100000); - _mCodec = new PlainTextMessageCodec(); - } - - #region IMessageSender Members - - public virtual bool HasSendingMessage - { - get { return _mQueue.Count > 0; } - } - - public void Initialize() - { - int len = _mClientConfig.Servers.Count; - - for (int i = 0; i < len; i++) - { - TcpClient channel = CreateChannel(i); - - if (channel != null) - { - _mActiveChannel = channel; - _mActiveIndex = i; - break; - } - } - - ThreadPool.QueueUserWorkItem(ChannelManagementTask); - ThreadPool.QueueUserWorkItem(AsynchronousSendTask); - - Logger.Info("Thread(TcpMessageSender-ChannelManagementTask) started."); - Logger.Info("Thread(TcpMessageSender-AsynchronousSendTask) started."); - } - - public void Send(IMessageTree tree) - { - lock (_mQueue) - { - if (_mQueue.Count < 100000) - { - _mQueue.Add(tree); - } - else - { - // throw it away since the queue is full - _mErrors ++; - - if (_mStatistics != null) - { - _mStatistics.OnOverflowed(tree); - } - - if (_mErrors%100 == 0) - { - Logger.Warn("Can't send message to cat-server due to queue's full! Count: " + _mErrors); - } - } - } - } - - public void Shutdown() - { - _mActive = false; - - try - { - if (_mActiveChannel != null && _mActiveChannel.Connected) - { - _mActiveChannel.Close(); - } - } - catch - { - // ignore it - } - } - - #endregion - - public void ChannelManagementTask(object o) - { - while (true) - { - if (_mActive) - { - if (_mActiveChannel == null || !_mActiveChannel.Connected) - { - if (_mActiveChannel != null) - Logger.Warn("ChannelManagementTask中,Socket关闭"); - _mActiveIndex = _mClientConfig.Servers.Count; - } - - for (int i = 0; i < _mActiveIndex; i++) - { - TcpClient channel = CreateChannel(i); - - if (channel != null) - { - _mLastChannel = _mActiveChannel; - _mActiveChannel = channel; - _mActiveIndex = i; - break; - } - } - } - - Thread.Sleep(5*1000); // every 2 seconds - } - } - - public void AsynchronousSendTask(object o) - { - while (true) - { - if (_mActive) - { - while (_mQueue.Count == 0 || _mActiveChannel == null || !_mActiveChannel.Connected) - { - if (_mActiveChannel != null && !_mActiveChannel.Connected) - Logger.Warn("AsynchronousSendTask中,Socket关闭"); - Thread.Sleep(5*1000); - } - - IMessageTree tree = null; - - lock (_mQueue) - { - foreach (IMessageTree t in _mQueue) - { - tree = t; - break; - } - - _mQueue.RemoveAt(0); - } - - try - { - SendInternal(tree); - if (tree != null) tree.Message = null; - } - catch (Exception t) - { - Logger.Error("Error when sending message over TCP socket! Error: {0}", t); - } - } - else - { - Thread.Sleep(5*1000); - } - } - } - - private void SendInternal(IMessageTree tree) - { - if (_mLastChannel != null) - { - try - { - Logger.Warn("SendInternal中,_mLastChannel关闭"); - _mLastChannel.Close(); - } - catch - { - // ignore it - } - - _mLastChannel = null; - } - - if (_mActiveChannel != null && _mActiveChannel.Connected) - { - ChannelBuffer buf = new ChannelBuffer(8192); - - _mCodec.Encode(tree, buf); - - byte[] data = buf.ToArray(); - - _mActiveChannel.Client.Send(data); - - if (_mStatistics != null) - { - _mStatistics.OnBytes(data.Length); - } - } - else - { - Logger.Warn("SendInternal中,Socket关闭"); - } - } - - private TcpClient CreateChannel(int index) - { - Server server = _mClientConfig.Servers[index]; - - if (!server.Enabled) - { - return null; - } - - TcpClient socket = new TcpClient(); - - socket.NoDelay = true; - socket.ReceiveTimeout = 2*1000; // 2 seconds - - string ip = server.Ip; - int port = server.Port; - - Logger.Info("Connecting to server({0}:{1}) ...", ip, port); - - try - { - socket.Connect(ip, port); - - if (socket.Connected) - { - Logger.Info("Connected to server({0}:{1}).", ip, port); - - return socket; - } - Logger.Error("Failed to connect to server({0}:{1}).", ip, port); - } - catch (Exception e) - { - Logger.Error( - "Failed to connect to server({0}:{1}). Error: {2}.", - ip, - port, - e.Message - ); - } - - return null; - } - } +using System; +using Com.Dianping.Cat.Configuration; +using Com.Dianping.Cat.Message.Spi.Codec; +using Com.Dianping.Cat.Util; +using System.Collections.Generic; +using System.Net.Sockets; +using System.Threading; + +namespace Com.Dianping.Cat.Message.Spi.IO +{ + public class TcpMessageSender : IMessageSender + { + private readonly ClientConfig _mClientConfig; + private readonly IMessageCodec _mCodec; + private readonly IList _mQueue; + private readonly IMessageStatistics _mStatistics; + private bool _mActive; + private TcpClient _mActiveChannel; + private int _mActiveIndex; + private int _mErrors; + private TcpClient _mLastChannel; + + public TcpMessageSender(ClientConfig clientConfig, IMessageStatistics statistics) + { + _mClientConfig = clientConfig; + _mStatistics = statistics; + _mActive = true; + _mQueue = new List(100000); + _mCodec = new PlainTextMessageCodec(); + } + + #region IMessageSender Members + + public virtual bool HasSendingMessage + { + get { return _mQueue.Count > 0; } + } + + public void Initialize() + { + int len = _mClientConfig.Servers.Count; + + for (int i = 0; i < len; i++) + { + TcpClient channel = CreateChannel(i); + + if (channel != null) + { + _mActiveChannel = channel; + _mActiveIndex = i; + break; + } + } + + ThreadPool.QueueUserWorkItem(ChannelManagementTask); + ThreadPool.QueueUserWorkItem(AsynchronousSendTask); + + Logger.Info("Thread(TcpMessageSender-ChannelManagementTask) started."); + Logger.Info("Thread(TcpMessageSender-AsynchronousSendTask) started."); + } + + public void Send(IMessageTree tree) + { + lock (_mQueue) + { + if (_mQueue.Count < 100000) + { + _mQueue.Add(tree); + } + else + { + // throw it away since the queue is full + _mErrors++; + + if (_mStatistics != null) + { + _mStatistics.OnOverflowed(tree); + } + + if (_mErrors % 100 == 0) + { + Logger.Warn("Can't send message to cat-server due to queue's full! Count: " + _mErrors); + } + } + } + } + + public void Shutdown() + { + _mActive = false; + + try + { + if (_mActiveChannel != null && _mActiveChannel.Connected) + { + _mActiveChannel.Close(); + } + } + catch + { + // ignore it + } + } + + #endregion + + public void ChannelManagementTask(object o) + { + while (true) + { + if (_mActive) + { + if (_mActiveChannel == null || !_mActiveChannel.Connected) + { + if (_mActiveChannel != null) + Logger.Warn("ChannelManagementTask中,Socket关闭"); + _mActiveIndex = _mClientConfig.Servers.Count; + } + + for (int i = 0; i < _mActiveIndex; i++) + { + TcpClient channel = CreateChannel(i); + + if (channel != null) + { + _mLastChannel = _mActiveChannel; + _mActiveChannel = channel; + _mActiveIndex = i; + break; + } + } + } + + Thread.Sleep(5 * 1000); // every 2 seconds + } + } + + public void AsynchronousSendTask(object o) + { + while (true) + { + if (_mActive) + { + while (_mQueue.Count == 0 || _mActiveChannel == null || !_mActiveChannel.Connected) + { + if (_mActiveChannel != null && !_mActiveChannel.Connected) + Logger.Warn("AsynchronousSendTask中,Socket关闭"); + Thread.Sleep(5 * 1000); + } + + IMessageTree tree = null; + + lock (_mQueue) + { + foreach (IMessageTree t in _mQueue) + { + tree = t; + break; + } + + _mQueue.RemoveAt(0); + } + + try + { + SendInternal(tree); + if (tree != null) tree.Message = null; + } + catch (Exception t) + { + Logger.Error("Error when sending message over TCP socket! Error: {0}", t); + } + } + else + { + Thread.Sleep(5 * 1000); + } + } + } + + private void SendInternal(IMessageTree tree) + { + if (_mLastChannel != null) + { + try + { + Logger.Warn("SendInternal中,_mLastChannel关闭"); + _mLastChannel.Close(); + } + catch + { + // ignore it + } + + _mLastChannel = null; + } + + if (_mActiveChannel != null && _mActiveChannel.Connected) + { + ChannelBuffer buf = new ChannelBuffer(8192); + + _mCodec.Encode(tree, buf); + + byte[] data = buf.ToArray(); + + _mActiveChannel.Client.Send(data); + + if (_mStatistics != null) + { + _mStatistics.OnBytes(data.Length); + } + } + else + { + Logger.Warn("SendInternal中,Socket关闭"); + } + } + + private TcpClient CreateChannel(int index) + { + Server server = _mClientConfig.Servers[index]; + + if (!server.Enabled) + { + return null; + } + + TcpClient socket = new TcpClient(); + + socket.NoDelay = true; + socket.ReceiveTimeout = 2 * 1000; // 2 seconds + + string ip = server.Ip; + int port = server.Port; + + Logger.Info("Connecting to server({0}:{1}) ...", ip, port); + + try + { + socket.Connect(ip, port); + + if (socket.Connected) + { + Logger.Info("Connected to server({0}:{1}).", ip, port); + + return socket; + } + Logger.Error("Failed to connect to server({0}:{1}).", ip, port); + } + catch (Exception e) + { + Logger.Error( + "Failed to connect to server({0}:{1}). Error: {2}.", + ip, + port, + e.Message + ); + } + + return null; + } + } } \ No newline at end of file diff --git a/Message/Spi/Internals/DefaultMessageManager.cs b/Message/Spi/Internals/DefaultMessageManager.cs index 19261b2..1cdad24 100644 --- a/Message/Spi/Internals/DefaultMessageManager.cs +++ b/Message/Spi/Internals/DefaultMessageManager.cs @@ -1,343 +1,344 @@ -using System.Globalization; -using Com.Dianping.Cat.Message.Internals; -using Com.Dianping.Cat.Message.Spi.IO; -using Com.Dianping.Cat.Util; -using Com.Dianping.Cat.Configuration; -using System; -using System.Collections.Generic; -using System.Threading; - -namespace Com.Dianping.Cat.Message.Spi.Internals -{ - public class DefaultMessageManager : IMessageManager - { - // we don't use static modifier since MessageManager is a singleton in - // production actually - private readonly CatThreadLocal _mContext = new CatThreadLocal(); - - private ClientConfig _mClientConfig; - - private MessageIdFactory _mFactory; - - private bool _mFirstMessage = true; - private String _mHostName; - - private IMessageSender _mSender; - - private IMessageStatistics _mStatistics; - - private StatusUpdateTask _mStatusUpdateTask; - - #region IMessageManager Members - - public virtual ClientConfig ClientConfig - { - get { return _mClientConfig; } - } - - public virtual ITransaction PeekTransaction - { - get - { - Context ctx = GetContext(); - - return ctx != null ? ctx.PeekTransaction() : null; - } - } - - public virtual IMessageTree ThreadLocalMessageTree - { - get - { - Context ctx = _mContext.Value; - - return ctx != null ? ctx.Tree : null; - } - } - - public virtual void Reset() - { - // destroy current thread local data - _mContext.Dispose(); - } - - public virtual void InitializeClient(ClientConfig clientConfig) - { - _mClientConfig = clientConfig ?? new ClientConfig(); - - _mHostName = NetworkInterfaceManager.GetLocalHostName(); - - _mStatistics = new DefaultMessageStatistics(); - _mSender = new TcpMessageSender(_mClientConfig, _mStatistics); - _mSender.Initialize(); - _mFactory = new MessageIdFactory(); - _mStatusUpdateTask = new StatusUpdateTask(_mStatistics); - - // initialize domain and ip address - _mFactory.Initialize(_mClientConfig.Domain.Id); - - // start status update task - ThreadPool.QueueUserWorkItem(_mStatusUpdateTask.Run); - - Logger.Info("Thread(StatusUpdateTask) started."); - } - - public virtual bool HasContext() - { - return _mContext.Value != null; - } - - public virtual bool CatEnabled - { - get { return _mClientConfig.Domain.Enabled && _mContext.Value != null; } - } - - public virtual void Add(IMessage message) - { - Context ctx = GetContext(); - - if (ctx != null) - { - ctx.Add(this, message); - } - else - Logger.Warn("Context没取到"); - } - - public virtual void Setup() - { - Context ctx = new Context(_mClientConfig.Domain.Id, _mHostName, - NetworkInterfaceManager.GetLocalHostAddress()); - - _mContext.Value = ctx; - } - - public virtual void Start(ITransaction transaction) - { - Context ctx = GetContext(); - - if (ctx != null) - { - ctx.Start(this, transaction); - } - else if (_mFirstMessage) - { - _mFirstMessage = false; - Logger.Info("CAT client is not enabled because it's not initialized yet"); - } - else - Logger.Warn("Context没取到"); - } - - public virtual void End(ITransaction transaction) - { - Context ctx = GetContext(); - - if (ctx != null) - { - //if (!transaction.Standalone) return; - if (ctx.End(this, transaction)) - { - _mContext.Dispose(); - } - } - else - Logger.Warn("Context没取到"); - } - - #endregion - - public MessageIdFactory GetMessageIdFactory() - { - return _mFactory; - } - - internal void Flush(IMessageTree tree) - { - if (_mSender != null) - { - _mSender.Send(tree); - - if (_mStatistics != null) - { - _mStatistics.OnSending(tree); - } - } - } - - internal Context GetContext() - { - if (Cat.IsInitialized()) - { - Context ctx = _mContext.Value; - - if (ctx != null) - { - return ctx; - } - if (_mClientConfig.DevMode) - { - throw new Exception( - "Cat has not been initialized successfully, please call Cal.setup(...) first for each thread."); - } - } - - return null; - } - - internal String NextMessageId() - { - return _mFactory.GetNextId(); - } - - //internal bool ShouldThrottle(IMessageTree tree) - //{ - // return false; - //} - - #region Nested type: Context - - internal class Context - { - private readonly Stack _mStack; - private readonly IMessageTree _mTree; - - public Context(String domain, String hostName, String ipAddress) - { - _mTree = new DefaultMessageTree(); - _mStack = new Stack(); - - Thread thread = Thread.CurrentThread; - String groupName = Thread.GetDomain().FriendlyName; - - _mTree.ThreadGroupName = groupName; - _mTree.ThreadId = thread.ManagedThreadId.ToString(CultureInfo.InvariantCulture); - _mTree.ThreadName = thread.Name; - - _mTree.Domain = domain; - _mTree.HostName = hostName; - _mTree.IpAddress = ipAddress; - } - - public IMessageTree Tree - { - get { return _mTree; } - } - - /// - /// 添加Event和Heartbeat - /// - /// - /// - public void Add(DefaultMessageManager manager, IMessage message) - { - if ((_mStack.Count == 0)) - { - IMessageTree tree = _mTree.Copy(); - tree.MessageId = manager.NextMessageId(); - tree.Message = message; - manager.Flush(tree); - } - else - { - ITransaction entry = _mStack.Peek(); - entry.AddChild(message); - } - } - - /// - /// return true means the transaction has been flushed. - /// - /// - /// - /// true if message is flushed, false otherwise - public bool End(DefaultMessageManager manager, ITransaction transaction) - { - if (_mStack.Count != 0) - { - ITransaction current = _mStack.Pop(); - while (transaction != current && _mStack.Count != 0) - { - current = _mStack.Pop(); - } - if (transaction != current) - throw new Exception("没找到对应的Transaction."); - - if (_mStack.Count == 0) - { - ValidateTransaction(current); - - IMessageTree tree = _mTree.Copy(); - _mTree.MessageId = null; - _mTree.Message = null; - manager.Flush(tree); - return true; - } - return false; - } - - throw new Exception("Stack为空, 没找到对应的Transaction."); - } - - /// - /// 返回stack的顶部对象 - /// - /// - public ITransaction PeekTransaction() - { - return (_mStack.Count == 0) ? null : _mStack.Peek(); - } - - /// - /// 添加transaction - /// - /// - /// - public void Start(DefaultMessageManager manager, ITransaction transaction) - { - if (_mStack.Count != 0) - { - transaction.Standalone = false; - ITransaction entry = _mStack.Peek(); - entry.AddChild(transaction); - } - else - { - _mTree.MessageId = manager.NextMessageId(); - _mTree.Message = transaction; - } - - _mStack.Push(transaction); - } - - //验证Transaction - internal void ValidateTransaction(ITransaction transaction) - { - IList children = transaction.Children; - int len = children.Count; - for (int i = 0; i < len; i++) - { - IMessage message = children[i]; - var transaction1 = message as ITransaction; - if (transaction1 != null) - { - ValidateTransaction(transaction1); - } - } - - if (!transaction.IsCompleted()) - { - // missing transaction end, log a BadInstrument event so that - // developer can fix the code - IMessage notCompleteEvent = new DefaultEvent("CAT", "BadInstrument") - {Status = "TransactionNotCompleted"}; - notCompleteEvent.Complete(); - transaction.AddChild(notCompleteEvent); - transaction.Complete(); - } - } - } - - #endregion - } +using System.Globalization; +using Com.Dianping.Cat.Message.Internals; +using Com.Dianping.Cat.Message.Spi.IO; +using Com.Dianping.Cat.Util; +using Com.Dianping.Cat.Configuration; +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Com.Dianping.Cat.Message.Spi.Internals +{ + [Serializable] + public class DefaultMessageManager : IMessageManager + { + // we don't use static modifier since MessageManager is a singleton in + // production actually + private readonly CatThreadLocal _mContext = new CatThreadLocal(); + + private ClientConfig _mClientConfig; + + private MessageIdFactory _mFactory; + + private bool _mFirstMessage = true; + private String _mHostName; + + private IMessageSender _mSender; + + private IMessageStatistics _mStatistics; + + private StatusUpdateTask _mStatusUpdateTask; + + #region IMessageManager Members + + public virtual ClientConfig ClientConfig + { + get { return _mClientConfig; } + } + + public virtual ITransaction PeekTransaction + { + get + { + Context ctx = GetContext(); + + return ctx != null ? ctx.PeekTransaction() : null; + } + } + + public virtual IMessageTree ThreadLocalMessageTree + { + get + { + Context ctx = _mContext.Value; + + return ctx != null ? ctx.Tree : null; + } + } + + public virtual void Reset() + { + // destroy current thread local data + _mContext.Dispose(); + } + + public virtual void InitializeClient(ClientConfig clientConfig) + { + _mClientConfig = clientConfig ?? new ClientConfig(); + + _mHostName = NetworkInterfaceManager.GetLocalHostName(); + + _mStatistics = new DefaultMessageStatistics(); + _mSender = new TcpMessageSender(_mClientConfig, _mStatistics); + _mSender.Initialize(); + _mFactory = new MessageIdFactory(); + _mStatusUpdateTask = new StatusUpdateTask(_mStatistics); + + // initialize domain and ip address + _mFactory.Initialize(_mClientConfig.Domain.Id); + + // start status update task + // ThreadPool.QueueUserWorkItem(_mStatusUpdateTask.Run); + + Logger.Info("Thread(StatusUpdateTask) started."); + } + + public virtual bool HasContext() + { + return _mContext.Value != null; + } + + public virtual bool CatEnabled + { + get { return _mClientConfig.Domain.Enabled && _mContext.Value != null; } + } + + public virtual void Add(IMessage message) + { + Context ctx = GetContext(); + + if (ctx != null) + { + ctx.Add(this, message); + } + else + Logger.Warn("Context没取到"); + } + + public virtual void Setup() + { + Context ctx = new Context(_mClientConfig.Domain.Id, _mHostName, + NetworkInterfaceManager.GetLocalHostAddress()); + + _mContext.Value = ctx; + } + + public virtual void Start(ITransaction transaction) + { + Context ctx = GetContext(); + + if (ctx != null) + { + ctx.Start(this, transaction); + } + else if (_mFirstMessage) + { + _mFirstMessage = false; + Logger.Info("CAT client is not enabled because it's not initialized yet"); + } + else + Logger.Warn("Context没取到"); + } + + public virtual void End(ITransaction transaction) + { + Context ctx = GetContext(); + + if (ctx != null) + { + //if (!transaction.Standalone) return; + if (ctx.End(this, transaction)) + { + _mContext.Dispose(); + } + } + else + Logger.Warn("Context没取到"); + } + + #endregion + + public MessageIdFactory GetMessageIdFactory() + { + return _mFactory; + } + + internal void Flush(IMessageTree tree) + { + if (_mSender != null) + { + _mSender.Send(tree); + + if (_mStatistics != null) + { + _mStatistics.OnSending(tree); + } + } + } + + internal Context GetContext() + { + if (Cat.IsInitialized()) + { + Context ctx = _mContext.Value; + + if (ctx != null) + { + return ctx; + } + if (_mClientConfig.DevMode) + { + throw new Exception( + "Cat has not been initialized successfully, please call Cal.setup(...) first for each thread."); + } + } + + return null; + } + + public String NextMessageId() + { + return _mFactory.GetNextId(); + } + + //internal bool ShouldThrottle(IMessageTree tree) + //{ + // return false; + //} + + #region Nested type: Context + + internal class Context + { + private readonly Stack _mStack; + private readonly IMessageTree _mTree; + + public Context(String domain, String hostName, String ipAddress) + { + _mTree = new DefaultMessageTree(); + _mStack = new Stack(); + + Thread thread = Thread.CurrentThread; + String groupName = Thread.GetDomain().FriendlyName; + + _mTree.ThreadGroupName = groupName; + _mTree.ThreadId = thread.ManagedThreadId.ToString(CultureInfo.InvariantCulture); + _mTree.ThreadName = thread.Name; + + _mTree.Domain = domain; + _mTree.HostName = hostName; + _mTree.IpAddress = ipAddress; + } + + public IMessageTree Tree + { + get { return _mTree; } + } + + /// + /// 添加Event和Heartbeat + /// + /// + /// + public void Add(DefaultMessageManager manager, IMessage message) + { + if ((_mStack.Count == 0)) + { + IMessageTree tree = _mTree.Copy(); + tree.MessageId = manager.NextMessageId(); + tree.Message = message; + manager.Flush(tree); + } + else + { + ITransaction entry = _mStack.Peek(); + entry.AddChild(message); + } + } + + /// + /// return true means the transaction has been flushed. + /// + /// + /// + /// true if message is flushed, false otherwise + public bool End(DefaultMessageManager manager, ITransaction transaction) + { + if (_mStack.Count != 0) + { + ITransaction current = _mStack.Pop(); + while (transaction != current && _mStack.Count != 0) + { + current = _mStack.Pop(); + } + if (transaction != current) + throw new Exception("没找到对应的Transaction."); + + if (_mStack.Count == 0) + { + ValidateTransaction(current); + + IMessageTree tree = _mTree.Copy(); + _mTree.MessageId = null; + _mTree.Message = null; + manager.Flush(tree); + return true; + } + return false; + } + throw new Exception("Stack为空, 没找到对应的Transaction."); + + + } + + /// + /// 返回stack的顶部对象 + /// + /// + public ITransaction PeekTransaction() + { + return (_mStack.Count == 0) ? null : _mStack.Peek(); + } + + /// + /// 添加transaction + /// + /// + /// + public void Start(DefaultMessageManager manager, ITransaction transaction) + { + if (_mStack.Count != 0) + { + transaction.Standalone = false; + ITransaction entry = _mStack.Peek(); + entry.AddChild(transaction); + } + else + { + _mTree.MessageId = manager.NextMessageId(); + _mTree.Message = transaction; + } + + _mStack.Push(transaction); + } + + //验证Transaction + internal void ValidateTransaction(ITransaction transaction) + { + IList children = transaction.Children; + int len = children.Count; + for (int i = 0; i < len; i++) + { + IMessage message = children[i]; + var transaction1 = message as ITransaction; + if (transaction1 != null) + { + ValidateTransaction(transaction1); + } + } + + if (!transaction.IsCompleted()) + { + // missing transaction end, log a BadInstrument event so that + // developer can fix the code + IMessage notCompleteEvent = new DefaultEvent("CAT", "BadInstrument") { Status = "TransactionNotCompleted" }; + notCompleteEvent.Complete(); + transaction.AddChild(notCompleteEvent); + transaction.Complete(); + } + } + } + + #endregion + } } \ No newline at end of file diff --git a/Message/Spi/Internals/DefaultMessageProducer.cs b/Message/Spi/Internals/DefaultMessageProducer.cs index cf3afcb..1622f59 100644 --- a/Message/Spi/Internals/DefaultMessageProducer.cs +++ b/Message/Spi/Internals/DefaultMessageProducer.cs @@ -1,129 +1,172 @@ -using Com.Dianping.Cat.Message.Internals; -using System; -using System.IO; - -namespace Com.Dianping.Cat.Message.Spi.Internals -{ - public class DefaultMessageProducer : IMessageProducer - { - private readonly IMessageManager _mManager; - - public DefaultMessageProducer(IMessageManager manager) - { - _mManager = manager; - } - - #region IMessageProducer Members - - public virtual void LogError(Exception cause) - { - var ignore = false; - if (cause.Data.Contains("CatIgnore") && cause.Data["CatIgnore"] is bool) - ignore = (bool) (cause.Data["CatIgnore"]); - - if (ignore) return; - - StringWriter writer = new StringWriter(); - - try - { - writer.WriteLine(cause.Message); - writer.WriteLine(cause.StackTrace); - var innerException = cause.InnerException; - while (innerException != null) - { - writer.WriteLine("-------------------------------------------------------------------"); - writer.WriteLine(innerException.Message); - writer.WriteLine(innerException.StackTrace); - - innerException = innerException.InnerException; - } - } - catch - { - } - - LogEvent("Error", cause.GetType().FullName, "ERROR", - writer.ToString()); - } - - public virtual void LogEvent(String type, String name, String status, String nameValuePairs) - { - IEvent evt0 = NewEvent(type, name); - - if (!string.IsNullOrEmpty(nameValuePairs)) - { - evt0.AddData(nameValuePairs); - } - - evt0.Status = status; - evt0.Complete(); - } - - public virtual void LogHeartbeat(String type, String name, String status, String nameValuePairs) - { - IHeartbeat heartbeat = NewHeartbeat(type, name); - - if (!string.IsNullOrEmpty(nameValuePairs)) - { - heartbeat.AddData(nameValuePairs); - } - heartbeat.Status = status; - heartbeat.Complete(); - } - - public virtual IEvent NewEvent(String type, String name) - { - if (!_mManager.HasContext()) - { - _mManager.Setup(); - } - - if (_mManager.CatEnabled) - { - IEvent evt0 = new DefaultEvent(type, name); - - _mManager.Add(evt0); - return evt0; - } - return new NullEvent(); - } - - public virtual IHeartbeat NewHeartbeat(String type, String name) - { - if (!_mManager.HasContext()) - { - _mManager.Setup(); - } - - if (_mManager.CatEnabled) - { - IHeartbeat heartbeat = new DefaultHeartbeat(type, name); - - _mManager.Add(heartbeat); - return heartbeat; - } - return new NullHeartbeat(); - } - - public virtual ITransaction NewTransaction(String type, String name) - { - // this enable CAT client logging cat message without explicit setup - if (!_mManager.HasContext()) - { - _mManager.Setup(); - } - - if (_mManager.CatEnabled) - { - ITransaction transaction = new DefaultTransaction(type, name, _mManager.End); - - _mManager.Start(transaction); - return transaction; - } - return new NullTransaction(); - } - - #endregion - } +using Com.Dianping.Cat.Message.Internals; +using System; +using System.IO; + +namespace Com.Dianping.Cat.Message.Spi.Internals +{ + public class DefaultMessageProducer : IMessageProducer + { + private readonly IMessageManager _mManager; + + public DefaultMessageProducer(IMessageManager manager) + { + _mManager = manager; + } + + public String CreateMessageId() + { + return _mManager.GetMessageIdFactory().GetNextId(); + } + + #region IMessageProducer Members + + public virtual void LogError(Exception cause) + { + var ignore = false; + if (cause.Data.Contains("CatIgnore") && cause.Data["CatIgnore"] is bool) + ignore = (bool)(cause.Data["CatIgnore"]); + + if (ignore) return; + + StringWriter writer = new StringWriter(); + + try + { + writer.WriteLine(cause.Message); + writer.WriteLine(cause.StackTrace); + var innerException = cause.InnerException; + while (innerException != null) + { + writer.WriteLine("-------------------------------------------------------------------"); + writer.WriteLine(innerException.Message); + writer.WriteLine(innerException.StackTrace); + + innerException = innerException.InnerException; + } + } + catch + { + } + + LogEvent("Error", cause.GetType().FullName, "ERROR", + writer.ToString()); + } + + public virtual void LogEvent(String type, String name, String status, String nameValuePairs) + { + IEvent evt0 = NewEvent(type, name); + + if (!string.IsNullOrEmpty(nameValuePairs)) + { + evt0.AddData(nameValuePairs); + } + + evt0.Status = status; + evt0.Complete(); + } + + public virtual void LogHeartbeat(String type, String name, String status, String nameValuePairs) + { + IHeartbeat heartbeat = NewHeartbeat(type, name); + + if (!string.IsNullOrEmpty(nameValuePairs)) + { + heartbeat.AddData(nameValuePairs); + } + heartbeat.Status = status; + heartbeat.Complete(); + } + + public virtual void LogMetric(String name, String status, String nameValuePairs) + { + String type = string.Empty; + IMetric metric = NewMetric(type, name); + + if (!string.IsNullOrWhiteSpace(nameValuePairs)) + { + metric.AddData(nameValuePairs); + } + + metric.Status = status; + metric.Complete(); + } + + public virtual IEvent NewEvent(String type, String name) + { + if (!_mManager.HasContext()) + { + _mManager.Setup(); + } + + if (_mManager.CatEnabled) + { + IEvent evt0 = new DefaultEvent(type, name); + + _mManager.Add(evt0); + return evt0; + } + return new NullEvent(); + } + + public virtual IHeartbeat NewHeartbeat(String type, String name) + { + if (!_mManager.HasContext()) + { + _mManager.Setup(); + } + + if (_mManager.CatEnabled) + { + IHeartbeat heartbeat = new DefaultHeartbeat(type, name); + + _mManager.Add(heartbeat); + return heartbeat; + } + return new NullHeartbeat(); + } + + public virtual ITransaction NewTransaction(String type, String name) + { + // this enable CAT client logging cat message without explicit setup + if (!_mManager.HasContext()) + { + _mManager.Setup(); + } + + if (_mManager.CatEnabled) + { + ITransaction transaction = new DefaultTransaction(type, name, _mManager.End); + + _mManager.Start(transaction); + return transaction; + } + return new NullTransaction(); + } + + /// + /// new metric + /// + /// group + /// key + public virtual IMetric NewMetric(String type, String name) + { + // this enable CAT client logging cat message without explicit setup + if (!_mManager.HasContext()) + { + _mManager.Setup(); + } + + if (_mManager.CatEnabled) + { + IMetric metric = new DefaultMetric(string.IsNullOrWhiteSpace(type) ? string.Empty : type, name); + + _mManager.Add(metric); + return metric; + } + return new NullMetric(); + } + + #endregion + + } } \ No newline at end of file diff --git a/Message/Spi/Internals/DefaultMessageStatistics.cs b/Message/Spi/Internals/DefaultMessageStatistics.cs index 9ddc50c..a7990bc 100644 --- a/Message/Spi/Internals/DefaultMessageStatistics.cs +++ b/Message/Spi/Internals/DefaultMessageStatistics.cs @@ -1,30 +1,30 @@ -namespace Com.Dianping.Cat.Message.Spi.Internals -{ - public class DefaultMessageStatistics : IMessageStatistics - { - #region IMessageStatistics Members - - public long Produced { get; set; } - - public long Overflowed { get; set; } - - public long Bytes { get; set; } - - public void OnSending(IMessageTree tree) - { - Produced++; - } - - public void OnOverflowed(IMessageTree tree) - { - Overflowed++; - } - - public void OnBytes(int size) - { - Bytes += size; - } - - #endregion - } +namespace Com.Dianping.Cat.Message.Spi.Internals +{ + public class DefaultMessageStatistics : IMessageStatistics + { + #region IMessageStatistics Members + + public long Produced { get; set; } + + public long Overflowed { get; set; } + + public long Bytes { get; set; } + + public void OnSending(IMessageTree tree) + { + Produced++; + } + + public void OnOverflowed(IMessageTree tree) + { + Overflowed++; + } + + public void OnBytes(int size) + { + Bytes += size; + } + + #endregion + } } \ No newline at end of file diff --git a/Message/Spi/Internals/MessageIdFactory.cs b/Message/Spi/Internals/MessageIdFactory.cs index f45e874..d1d7411 100644 --- a/Message/Spi/Internals/MessageIdFactory.cs +++ b/Message/Spi/Internals/MessageIdFactory.cs @@ -1,86 +1,86 @@ -using Com.Dianping.Cat.Util; -using System; -using System.Text; - -namespace Com.Dianping.Cat.Message.Spi.Internals -{ - /// - /// 根据域名(配置指定的),系统IP(自动解析的,16进制字符串),时间戳(1970年到当前的小时数)和自增编号组成 - /// - public class MessageIdFactory - { - private String _mDomain; - private volatile int _mIndex; - - private String _mIpAddress; - private long _mLastTimestamp; - - public MessageIdFactory() - { - _mLastTimestamp = Timestamp; - } - - protected internal long Timestamp - { - get { return MilliSecondTimer.CurrentTimeHoursForJava(); } - } - - public String Domain - { - set { _mDomain = value; } - } - - public String IpAddress - { - set { _mIpAddress = value; } - } - - public String GetNextId() - { - long timestamp = Timestamp; - int index; - - lock (this) - { - if (timestamp != _mLastTimestamp) - { - _mIndex = 0; - _mLastTimestamp = timestamp; - } - - index = _mIndex++; - } - - StringBuilder sb = new StringBuilder(_mDomain.Length + 32); - - sb.Append(_mDomain); - sb.Append('-'); - sb.Append(_mIpAddress); - sb.Append('-'); - sb.Append(timestamp); - sb.Append('-'); - sb.Append(index); - - return sb.ToString(); - } - - public void Initialize(String domain) - { - _mDomain = domain; - - if (_mIpAddress != null) return; - - byte[] bytes = NetworkInterfaceManager.GetAddressBytes(); - - StringBuilder sb = new StringBuilder(); - - foreach (byte b in bytes) - { - sb.Append(((b >> 4) & 0x0F).ToString("x")); - sb.Append((b & 0x0F).ToString("x")); - } - - _mIpAddress = sb.ToString(); - } - } +using Com.Dianping.Cat.Util; +using System; +using System.Text; + +namespace Com.Dianping.Cat.Message.Spi.Internals +{ + /// + /// 根据域名(配置指定的),系统IP(自动解析的,16进制字符串),时间戳(1970年到当前的小时数)和自增编号组成 + /// + public class MessageIdFactory + { + private String _mDomain; + private volatile int _mIndex; + + private String _mIpAddress; + private long _mLastTimestamp; + + public MessageIdFactory() + { + _mLastTimestamp = Timestamp; + } + + protected internal long Timestamp + { + get { return MilliSecondTimer.CurrentTimeHoursForJava(); } + } + + public String Domain + { + set { _mDomain = value; } + } + + public String IpAddress + { + set { _mIpAddress = value; } + } + + public String GetNextId() + { + long timestamp = Timestamp; + int index; + + lock (this) + { + if (timestamp != _mLastTimestamp) + { + _mIndex = 0; + _mLastTimestamp = timestamp; + } + + index = _mIndex++; + } + + StringBuilder sb = new StringBuilder(_mDomain.Length + 32); + + sb.Append(_mDomain); + sb.Append('-'); + sb.Append(_mIpAddress); + sb.Append('-'); + sb.Append(timestamp); + sb.Append('-'); + sb.Append(index); + + return sb.ToString(); + } + + public void Initialize(String domain) + { + _mDomain = domain; + + if (_mIpAddress != null) return; + + byte[] bytes = NetworkInterfaceManager.GetAddressBytes(); + + StringBuilder sb = new StringBuilder(); + + foreach (byte b in bytes) + { + sb.Append(((b >> 4) & 0x0F).ToString("x")); + sb.Append((b & 0x0F).ToString("x")); + } + + _mIpAddress = sb.ToString(); + } + } } \ No newline at end of file diff --git a/Message/Spi/Internals/StatusUpdateTask.cs b/Message/Spi/Internals/StatusUpdateTask.cs index 649d44a..61f001a 100644 --- a/Message/Spi/Internals/StatusUpdateTask.cs +++ b/Message/Spi/Internals/StatusUpdateTask.cs @@ -1,192 +1,192 @@ -using System; -using System.Diagnostics; -using System.Globalization; -using System.Management; -using System.Threading; -using System.Text; -using Com.Dianping.Cat.Util; - -namespace Com.Dianping.Cat.Message.Spi.Internals -{ - public class StatusUpdateTask - { - private readonly IMessageStatistics _mStatistics; - - public StatusUpdateTask(IMessageStatistics mStatistics) - { - _mStatistics = mStatistics; - } - - /// - /// 获取系统内存大小 - /// - /// 内存大小(单位M) - private static int GetPhisicalMemory() - { - ManagementObjectSearcher searcher = new ManagementObjectSearcher(); //用于查询一些如系统信息的管理对象 - searcher.Query = new SelectQuery("Win32_PhysicalMemory ", "", new[] {"Capacity"}); //设置查询条件 - ManagementObjectCollection collection = searcher.Get(); //获取内存容量 - ManagementObjectCollection.ManagementObjectEnumerator em = collection.GetEnumerator(); - - long capacity = 0; - while (em.MoveNext()) - { - ManagementBaseObject baseObj = em.Current; - if (baseObj.Properties["Capacity"].Value != null) - { - try - { - capacity += long.Parse(baseObj.Properties["Capacity"].Value.ToString()); - } - catch - { - return 0; - } - } - } - return (int) (capacity/1024/1024); - } - - public void Run(object o) - { - while (true) - { - var sb = new StringBuilder(); - sb.AppendLine("StatusUpdateTask:"); - sb.AppendLine("Bytes=" + _mStatistics.Bytes); - sb.AppendLine("Overflowed=" + _mStatistics.Overflowed); - sb.AppendLine("Produced=" + _mStatistics.Produced); - - //机器的CPU内核数 - var processorCount = Environment.ProcessorCount; - sb.AppendLine("机器的CPU内核数=" + processorCount); - - //获取当前进程 - Process currentProcess = Process.GetCurrentProcess(); - //var processId = CurrentProcess.Id;//PID - //获取当前进程CPU利用率 - var tmpRate = - Math.Round( - currentProcess.UserProcessorTime.TotalMilliseconds*100/ - currentProcess.TotalProcessorTime.TotalMilliseconds, 2); - var cpuUsage = tmpRate + "%"; //CPU - //获取当前进程内存占用 - var memoryUsage = (currentProcess.WorkingSet64/1024/1024).ToString(CultureInfo.InvariantCulture) + "M (" + - (currentProcess.WorkingSet64/1024).ToString(CultureInfo.InvariantCulture) + "KB)"; - //占用内存 - //获取当前进程的线程数 - var threadCount = currentProcess.Threads.Count; //线程 - - //获取当前进程的线程池大小 - int maxThread, maxThread2; - ThreadPool.GetMaxThreads(out maxThread, out maxThread2); //线程 - int avThread, avThread2; - ThreadPool.GetAvailableThreads(out avThread, out avThread2); - int mThread, mThread2; - ThreadPool.GetMinThreads(out mThread, out mThread2); - - var threadPoolInfo = string.Format("线程池大小={0}/{1}, 线程池可用线程数={2}/{3}, 线程池最小线程数={4}/{5}", maxThread2, - maxThread, avThread2, avThread, mThread2, - mThread); - - sb.AppendLine("当前进程CPU利用率=" + cpuUsage); - sb.AppendLine("当前进程内存占用=" + memoryUsage); - sb.AppendLine("当前进程的线程数=" + threadCount); - sb.AppendLine(threadPoolInfo); - - var bestThreadInfo = string.Empty; - //最佳线程数为 - var bestThreadCountTmp = currentProcess.TotalProcessorTime.TotalMilliseconds/ - (currentProcess.UserProcessorTime.TotalMilliseconds/threadCount); - bestThreadInfo += "最佳线程数=" + bestThreadCountTmp + ","; - - //如果需要增加线程 - if (Math.Abs(bestThreadCountTmp - maxThread) > 1) - { - if (tmpRate < 90 && bestThreadCountTmp > 400) - { - int bestThreadCount = (int) Math.Floor(bestThreadCountTmp); - //ThreadPool.SetMinThreads(bestThreadCount, bestThreadCount); - ThreadPool.SetMaxThreads(bestThreadCount, bestThreadCount); - bestThreadInfo += "重设线程池的MaxThreads=" + bestThreadCount + ","; - } - } - sb.AppendLine(bestThreadInfo); - - var phisicalMemory = GetPhisicalMemory(); - sb.AppendLine("MemoryCapacity=" + phisicalMemory + "M"); - - PerformanceCounter ramCounter = new PerformanceCounter("Memory", "Available MBytes"); - double available = ramCounter.NextValue(); - - ////获取内存可用大小 - //ManagementClass cimobject2 = new ManagementClass("Win32_PerfFormattedData_PerfOS_Memory"); - //ManagementObjectCollection moc2 = cimobject2.GetInstances(); - //foreach (ManagementObject mo2 in moc2) - //{ - // available += int.Parse(mo2.Properties["AvailableMBytes"].Value.ToString(); - //} - //moc2.Dispose(); - //cimobject2.Dispose(); - - sb.AppendLine("MemoryAvailable=" + available + "M"); - sb.AppendLine("MemoryUsed=" + (phisicalMemory - available) + "M," + - Math.Round(((phisicalMemory - available)/phisicalMemory*100), 2) + "%"); - - PerformanceCounter cpuCounter = new PerformanceCounter - { - CategoryName = "Processor", - CounterName = "% Processor Time", - InstanceName = "_Total" - }; - sb.AppendLine("总CPU利用率=" + cpuCounter.NextValue() + "%"); - - //// Get the WMI class - //ManagementClass cc = new ManagementClass(new ManagementPath("Win32_Processor")); - //// Get the properties in the class - //ManagementObjectCollection moc = cc.GetInstances(); - //foreach (ManagementObject mo in moc) - //{ - // PropertyDataCollection properties = mo.Properties; //获取内核数代码 - // Console.WriteLine("物理内核数:" + properties["NumberOfCores"].Value); - // Console.WriteLine("逻辑内核数:" + properties["NumberOfLogicalProcessors"].Value); - // //其他属性获取代码 - // foreach (PropertyData property in properties) - // { - // Console.WriteLine(property.Name + ":" + property.Value); - // } - //} - //moc.Dispose(); - //cc.Dispose(); - - Logger.Info(sb.ToString()); - - var sb2 = new StringBuilder(); - sb2.Append("Bytes=" + _mStatistics.Bytes); - sb2.Append("&Overflowed=" + _mStatistics.Overflowed); - sb2.Append("&Produced=" + _mStatistics.Produced); - - sb2.AppendLine("&机器的CPU内核数=" + processorCount); - sb2.AppendLine("&当前进程CPU利用率=" + cpuUsage); - sb2.AppendLine("&当前进程内存占用=" + memoryUsage); - sb2.AppendLine("&当前进程的线程数=" + threadCount); - sb2.AppendLine("&" + threadPoolInfo); - sb2.AppendLine("&" + bestThreadInfo); - sb2.AppendLine("&MemoryCapacity=" + phisicalMemory + "M"); - sb2.AppendLine("&MemoryAvailable=" + available + "M"); - sb2.AppendLine("&MemoryUsed=" + (phisicalMemory - available) + "M," + - Math.Round(((phisicalMemory - available)/phisicalMemory*100), 2) + "%"); - sb2.AppendLine("&总CPU利用率=" + cpuCounter.NextValue() + "%"); - - Cat.GetProducer().LogHeartbeat("Cat", "Heartbeat", "0", sb2.ToString()); - Cat.GetProducer().LogEvent("Cat", "Heartbeat" + DateTime.Now.Minute, "0", sb2.ToString()); - - _mStatistics.Bytes = 0; - _mStatistics.Overflowed = 0; - _mStatistics.Produced = 0; - - Thread.Sleep(60000); - } - } - } +using System; +using System.Diagnostics; +using System.Globalization; +using System.Management; +using System.Threading; +using System.Text; +using Com.Dianping.Cat.Util; + +namespace Com.Dianping.Cat.Message.Spi.Internals +{ + public class StatusUpdateTask + { + private readonly IMessageStatistics _mStatistics; + + public StatusUpdateTask(IMessageStatistics mStatistics) + { + _mStatistics = mStatistics; + } + + /// + /// 获取系统内存大小 + /// + /// 内存大小(单位M) + private static int GetPhisicalMemory() + { + ManagementObjectSearcher searcher = new ManagementObjectSearcher(); //用于查询一些如系统信息的管理对象 + searcher.Query = new SelectQuery("Win32_PhysicalMemory ", "", new[] { "Capacity" }); //设置查询条件 + ManagementObjectCollection collection = searcher.Get(); //获取内存容量 + ManagementObjectCollection.ManagementObjectEnumerator em = collection.GetEnumerator(); + + long capacity = 0; + while (em.MoveNext()) + { + ManagementBaseObject baseObj = em.Current; + if (baseObj.Properties["Capacity"].Value != null) + { + try + { + capacity += long.Parse(baseObj.Properties["Capacity"].Value.ToString()); + } + catch + { + return 0; + } + } + } + return (int)(capacity / 1024 / 1024); + } + + public void Run(object o) + { + while (true) + { + var sb = new StringBuilder(); + sb.AppendLine("StatusUpdateTask:"); + sb.AppendLine("Bytes=" + _mStatistics.Bytes); + sb.AppendLine("Overflowed=" + _mStatistics.Overflowed); + sb.AppendLine("Produced=" + _mStatistics.Produced); + + //机器的CPU内核数 + var processorCount = Environment.ProcessorCount; + sb.AppendLine("机器的CPU内核数=" + processorCount); + + //获取当前进程 + Process currentProcess = Process.GetCurrentProcess(); + //var processId = CurrentProcess.Id;//PID + //获取当前进程CPU利用率 + var tmpRate = + Math.Round( + currentProcess.UserProcessorTime.TotalMilliseconds * 100 / + currentProcess.TotalProcessorTime.TotalMilliseconds, 2); + var cpuUsage = tmpRate + "%"; //CPU + //获取当前进程内存占用 + var memoryUsage = (currentProcess.WorkingSet64 / 1024 / 1024).ToString(CultureInfo.InvariantCulture) + "M (" + + (currentProcess.WorkingSet64 / 1024).ToString(CultureInfo.InvariantCulture) + "KB)"; + //占用内存 + //获取当前进程的线程数 + var threadCount = currentProcess.Threads.Count; //线程 + + //获取当前进程的线程池大小 + int maxThread, maxThread2; + ThreadPool.GetMaxThreads(out maxThread, out maxThread2); //线程 + int avThread, avThread2; + ThreadPool.GetAvailableThreads(out avThread, out avThread2); + int mThread, mThread2; + ThreadPool.GetMinThreads(out mThread, out mThread2); + + var threadPoolInfo = string.Format("线程池大小={0}/{1}, 线程池可用线程数={2}/{3}, 线程池最小线程数={4}/{5}", maxThread2, + maxThread, avThread2, avThread, mThread2, + mThread); + + sb.AppendLine("当前进程CPU利用率=" + cpuUsage); + sb.AppendLine("当前进程内存占用=" + memoryUsage); + sb.AppendLine("当前进程的线程数=" + threadCount); + sb.AppendLine(threadPoolInfo); + + var bestThreadInfo = string.Empty; + //最佳线程数为 + var bestThreadCountTmp = currentProcess.TotalProcessorTime.TotalMilliseconds / + (currentProcess.UserProcessorTime.TotalMilliseconds / threadCount); + bestThreadInfo += "最佳线程数=" + bestThreadCountTmp + ","; + + //如果需要增加线程 + if (Math.Abs(bestThreadCountTmp - maxThread) > 1) + { + if (tmpRate < 90 && bestThreadCountTmp > 400) + { + int bestThreadCount = (int)Math.Floor(bestThreadCountTmp); + //ThreadPool.SetMinThreads(bestThreadCount, bestThreadCount); + ThreadPool.SetMaxThreads(bestThreadCount, bestThreadCount); + bestThreadInfo += "重设线程池的MaxThreads=" + bestThreadCount + ","; + } + } + sb.AppendLine(bestThreadInfo); + + var phisicalMemory = GetPhisicalMemory(); + sb.AppendLine("MemoryCapacity=" + phisicalMemory + "M"); + + PerformanceCounter ramCounter = new PerformanceCounter("Memory", "Available MBytes"); + double available = ramCounter.NextValue(); + + ////获取内存可用大小 + //ManagementClass cimobject2 = new ManagementClass("Win32_PerfFormattedData_PerfOS_Memory"); + //ManagementObjectCollection moc2 = cimobject2.GetInstances(); + //foreach (ManagementObject mo2 in moc2) + //{ + // available += int.Parse(mo2.Properties["AvailableMBytes"].Value.ToString(); + //} + //moc2.Dispose(); + //cimobject2.Dispose(); + + sb.AppendLine("MemoryAvailable=" + available + "M"); + sb.AppendLine("MemoryUsed=" + (phisicalMemory - available) + "M," + + Math.Round(((phisicalMemory - available) / phisicalMemory * 100), 2) + "%"); + + PerformanceCounter cpuCounter = new PerformanceCounter + { + CategoryName = "Processor", + CounterName = "% Processor Time", + InstanceName = "_Total" + }; + sb.AppendLine("总CPU利用率=" + cpuCounter.NextValue() + "%"); + + //// Get the WMI class + //ManagementClass cc = new ManagementClass(new ManagementPath("Win32_Processor")); + //// Get the properties in the class + //ManagementObjectCollection moc = cc.GetInstances(); + //foreach (ManagementObject mo in moc) + //{ + // PropertyDataCollection properties = mo.Properties; //获取内核数代码 + // Console.WriteLine("物理内核数:" + properties["NumberOfCores"].Value); + // Console.WriteLine("逻辑内核数:" + properties["NumberOfLogicalProcessors"].Value); + // //其他属性获取代码 + // foreach (PropertyData property in properties) + // { + // Console.WriteLine(property.Name + ":" + property.Value); + // } + //} + //moc.Dispose(); + //cc.Dispose(); + + Logger.Info(sb.ToString()); + + var sb2 = new StringBuilder(); + sb2.Append("Bytes=" + _mStatistics.Bytes); + sb2.Append("&Overflowed=" + _mStatistics.Overflowed); + sb2.Append("&Produced=" + _mStatistics.Produced); + + sb2.AppendLine("&机器的CPU内核数=" + processorCount); + sb2.AppendLine("&当前进程CPU利用率=" + cpuUsage); + sb2.AppendLine("&当前进程内存占用=" + memoryUsage); + sb2.AppendLine("&当前进程的线程数=" + threadCount); + sb2.AppendLine("&" + threadPoolInfo); + sb2.AppendLine("&" + bestThreadInfo); + sb2.AppendLine("&MemoryCapacity=" + phisicalMemory + "M"); + sb2.AppendLine("&MemoryAvailable=" + available + "M"); + sb2.AppendLine("&MemoryUsed=" + (phisicalMemory - available) + "M," + + Math.Round(((phisicalMemory - available) / phisicalMemory * 100), 2) + "%"); + sb2.AppendLine("&总CPU利用率=" + cpuCounter.NextValue() + "%"); + + Cat.GetProducer().LogHeartbeat("Cat", "Heartbeat", "0", sb2.ToString()); + Cat.GetProducer().LogEvent("Cat", "Heartbeat" + DateTime.Now.Minute, "0", sb2.ToString()); + + _mStatistics.Bytes = 0; + _mStatistics.Overflowed = 0; + _mStatistics.Produced = 0; + + Thread.Sleep(60000); + } + } + } } \ No newline at end of file diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index abb13d7..4c3509b 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -1,4 +1,5 @@ -using System.Reflection; +using System.Reflection; +using System.Web; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. @@ -10,13 +11,13 @@ [assembly: AssemblyProduct("Cat")] [assembly: AssemblyCopyright("Copyright © Dianping.com 2013")] [assembly: AssemblyTrademark("Dianping.com")] -[assembly: AssemblyCulture("")] - +[assembly: AssemblyCulture("")] +[assembly: PreApplicationStartMethod(typeof(Com.Dianping.Cat.Cat), "RegisterHttpModule")] // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. -[assembly: AssemblyVersion("0.1.0")] +[assembly: AssemblyVersion("0.3.1.0")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. diff --git a/Util/AppEnv.cs b/Util/AppEnv.cs new file mode 100644 index 0000000..40a6fae --- /dev/null +++ b/Util/AppEnv.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Web; + +namespace Com.Dianping.Cat.Util +{ + public static class AppEnv + { + public static string IP { get { return getLocalIP(); } } + + private static string getLocalIP() + { + try + { + return NetworkInterfaceManager.GetLocalHostAddress(); + } + catch + { + return string.Empty; + } + } + + public static string GetClientIp(HttpRequest request) + { + if (request == null) + { + return string.Empty; + } + var serverVariables = request.ServerVariables["HTTP_X_FORWARDED_FOR"]; + if (!string.IsNullOrEmpty(serverVariables)) + { + var items = serverVariables.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + if (items.Length > 0) + { + return items[0]; + } + } + return request.ServerVariables["REMOTE_ADDR"]; + } + + public static string GetRemoteIp(HttpRequest request) + { + if (request == null) + { + return string.Empty; + } + return request.ServerVariables["REMOTE_ADDR"]; + } + } +} diff --git a/Util/CatThreadLocal.cs b/Util/CatThreadLocal.cs index 3d92ce8..68f9922 100644 --- a/Util/CatThreadLocal.cs +++ b/Util/CatThreadLocal.cs @@ -1,34 +1,34 @@ -using System.Collections; -using System.Threading; - -namespace Com.Dianping.Cat.Util -{ - public class CatThreadLocal - { - private readonly Hashtable _mValues = new Hashtable(1024); - - public T Value - { - get - { - int threadId = Thread.CurrentThread.ManagedThreadId; - object value = _mValues[threadId]; - - return (T) value; - } - set - { - int threadId = Thread.CurrentThread.ManagedThreadId; - - _mValues[threadId] = value; - } - } - - public void Dispose() - { - int threadId = Thread.CurrentThread.ManagedThreadId; - - _mValues.Remove(threadId); - } - } +using System.Collections; +using System.Threading; + +namespace Com.Dianping.Cat.Util +{ + public class CatThreadLocal + { + private readonly Hashtable _mValues = new Hashtable(1024); + + public T Value + { + get + { + int threadId = Thread.CurrentThread.ManagedThreadId; + object value = _mValues[threadId]; + + return (T)value; + } + set + { + int threadId = Thread.CurrentThread.ManagedThreadId; + + _mValues[threadId] = value; + } + } + + public void Dispose() + { + int threadId = Thread.CurrentThread.ManagedThreadId; + + _mValues.Remove(threadId); + } + } } \ No newline at end of file diff --git a/Util/Logger.cs b/Util/Logger.cs index 5cb4494..e40b5cd 100644 --- a/Util/Logger.cs +++ b/Util/Logger.cs @@ -1,67 +1,67 @@ -using System; -using System.IO; - -namespace Com.Dianping.Cat.Util -{ - /// - /// 简单记录Cat客户端的启动日志 - /// - public class Logger - { - private static StreamWriter _mWriter; - - public static void Info(string pattern, params object[] args) - { - Log("INFO", pattern, args); - } - - public static void Warn(string pattern, params object[] args) - { - Log("WARN", pattern, args); - } - - public static void Error(string pattern, params object[] args) - { - Log("ERROR", pattern, args); - } - - private static void Log(string severity, string pattern, params object[] args) - { - string timestamp = new DateTime(MilliSecondTimer.CurrentTimeMicros()*10L).ToString("yyyy-MM-dd HH:mm:ss.fff"); - string message = string.Format(pattern, args); - string line = "[" + timestamp + "] [" + severity + "] " + message; - - if (_mWriter != null) - { - _mWriter.WriteLine(line); - _mWriter.Flush(); - } - else - { - Console.WriteLine(line); - } - } - - /// - /// 初始化 - /// - /// - public static void Initialize(string logFile) - { - try - { - if (!File.Exists(logFile)) - { - var directoryInfo = new FileInfo(logFile).Directory; - if (directoryInfo != null) directoryInfo.Create(); - } - - _mWriter = new StreamWriter(logFile, true); - } - catch (Exception e) - { - Console.WriteLine("Error when openning log file: " + e.Message + " " + e.StackTrace + "."); - } - } - } +using System; +using System.IO; + +namespace Com.Dianping.Cat.Util +{ + /// + /// 简单记录Cat客户端的启动日志 + /// + public class Logger + { + private static StreamWriter _mWriter; + + public static void Info(string pattern, params object[] args) + { + Log("INFO", pattern, args); + } + + public static void Warn(string pattern, params object[] args) + { + Log("WARN", pattern, args); + } + + public static void Error(string pattern, params object[] args) + { + Log("ERROR", pattern, args); + } + + private static void Log(string severity, string pattern, params object[] args) + { + string timestamp = new DateTime(MilliSecondTimer.CurrentTimeMicros() * 10L).ToString("yyyy-MM-dd HH:mm:ss.fff"); + string message = string.Format(pattern, args); + string line = "[" + timestamp + "] [" + severity + "] " + message; + + if (_mWriter != null) + { + _mWriter.WriteLine(line); + _mWriter.Flush(); + } + else + { + Console.WriteLine(line); + } + } + + /// + /// 初始化 + /// + /// + public static void Initialize(string logFile) + { + try + { + if (!File.Exists(logFile)) + { + var directoryInfo = new FileInfo(logFile).Directory; + if (directoryInfo != null) directoryInfo.Create(); + } + + _mWriter = new StreamWriter(logFile, true); + } + catch (Exception e) + { + Console.WriteLine("Error when openning log file: " + e.Message + " " + e.StackTrace + "."); + } + } + } } \ No newline at end of file diff --git a/Util/MilliSecondTimer.cs b/Util/MilliSecondTimer.cs index c19d959..95df7dc 100644 --- a/Util/MilliSecondTimer.cs +++ b/Util/MilliSecondTimer.cs @@ -1,68 +1,68 @@ -using System; -using System.Runtime.InteropServices; - -namespace Com.Dianping.Cat.Util -{ - /// - /// This timer provides milli-second precise system time. - /// - public class MilliSecondTimer - { - public static long CurrentTimeMicros() - { - //return HighResTicksProvider.GetTickCount () / 10L; // it's microsecond precise - return DateTime.Now.Ticks/10L; // it's millisecond precise - } - - public static long CurrentTimeHoursForJava() - { - DateTime baseline = new DateTime(1970, 1, 1, 0, 0, 0); - TimeSpan ts = new TimeSpan(DateTime.UtcNow.Ticks - baseline.Ticks); - - return ((long) ts.TotalMilliseconds/3600000L); - } - } - - public class HighResTicksProvider - { - private static long _f; - - [DllImport("kernel32.dll")] - private static extern bool QueryPerformanceCounter([In, Out] ref long lpPerformanceCount); - - [DllImport("kernel32.dll")] - private static extern bool QueryPerformanceFrequency([In, Out] ref long lpFrequency); - - /// - /// 获得当前时间戳,十分之一微秒(100纳秒,和 DateTime.Now.Ticks 刻度一样) - /// - /// - public static long GetTickCount() - { - long f = _f; - - if (f == 0) - { - if (QueryPerformanceFrequency(ref f)) - { - _f = f; - } - else - { - _f = -1; - } - } - - if (_f == -1) - { - // fallback - return DateTime.Now.Ticks; - } - - long c = 0; - QueryPerformanceCounter(ref c); - - return (long) (((double) c)*1000*10000/(f)); - } - } +using System; +using System.Runtime.InteropServices; + +namespace Com.Dianping.Cat.Util +{ + /// + /// This timer provides milli-second precise system time. + /// + public class MilliSecondTimer + { + public static long CurrentTimeMicros() + { + //return HighResTicksProvider.GetTickCount () / 10L; // it's microsecond precise + return DateTime.Now.Ticks / 10L; // it's millisecond precise + } + + public static long CurrentTimeHoursForJava() + { + DateTime baseline = new DateTime(1970, 1, 1, 0, 0, 0); + TimeSpan ts = new TimeSpan(DateTime.UtcNow.Ticks - baseline.Ticks); + + return ((long)ts.TotalMilliseconds / 3600000L); + } + } + + public class HighResTicksProvider + { + private static long _f; + + [DllImport("kernel32.dll")] + private static extern bool QueryPerformanceCounter([In, Out] ref long lpPerformanceCount); + + [DllImport("kernel32.dll")] + private static extern bool QueryPerformanceFrequency([In, Out] ref long lpFrequency); + + /// + /// 获得当前时间戳,十分之一微秒(100纳秒,和 DateTime.Now.Ticks 刻度一样) + /// + /// + public static long GetTickCount() + { + long f = _f; + + if (f == 0) + { + if (QueryPerformanceFrequency(ref f)) + { + _f = f; + } + else + { + _f = -1; + } + } + + if (_f == -1) + { + // fallback + return DateTime.Now.Ticks; + } + + long c = 0; + QueryPerformanceCounter(ref c); + + return (long)(((double)c) * 1000 * 10000 / (f)); + } + } } \ No newline at end of file diff --git a/Util/NetworkInterfaceManager.cs b/Util/NetworkInterfaceManager.cs index 19b8e4c..0349f38 100644 --- a/Util/NetworkInterfaceManager.cs +++ b/Util/NetworkInterfaceManager.cs @@ -1,39 +1,39 @@ -using System; -using System.Linq; -using System.Net.Sockets; -using System.Net; - -namespace Com.Dianping.Cat.Util -{ - public class NetworkInterfaceManager - { - public static string GetLocalHostName() - { - return Dns.GetHostName(); - } - - public static string GetLocalHostAddress() - { - IPHostEntry host = Dns.GetHostEntry(GetLocalHostName()); - - foreach (IPAddress ip in host.AddressList.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork)) - { - return ip.ToString(); - } - - throw new NotSupportedException("No IP address found"); - } - - public static byte[] GetAddressBytes() - { - IPHostEntry host = Dns.GetHostEntry(GetLocalHostName()); - - foreach (IPAddress ip in host.AddressList.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork)) - { - return ip.GetAddressBytes(); - } - - throw new NotSupportedException("No IP address found"); - } - } +using System; +using System.Linq; +using System.Net.Sockets; +using System.Net; + +namespace Com.Dianping.Cat.Util +{ + public class NetworkInterfaceManager + { + public static string GetLocalHostName() + { + return Dns.GetHostName(); + } + + public static string GetLocalHostAddress() + { + IPHostEntry host = Dns.GetHostEntry(GetLocalHostName()); + + foreach (IPAddress ip in host.AddressList.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork)) + { + return ip.ToString(); + } + + throw new NotSupportedException("No IP address found"); + } + + public static byte[] GetAddressBytes() + { + IPHostEntry host = Dns.GetHostEntry(GetLocalHostName()); + + foreach (IPAddress ip in host.AddressList.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork)) + { + return ip.GetAddressBytes(); + } + + throw new NotSupportedException("No IP address found"); + } + } } \ No newline at end of file diff --git a/bin/Debug/Cat.dll b/bin/Debug/Cat.dll deleted file mode 100644 index e871f06..0000000 Binary files a/bin/Debug/Cat.dll and /dev/null differ diff --git a/bin/Debug/Cat.pdb b/bin/Debug/Cat.pdb deleted file mode 100644 index c534f03..0000000 Binary files a/bin/Debug/Cat.pdb and /dev/null differ diff --git a/obj/x86/Debug/Cat.Net.csproj.FileListAbsolute.txt b/obj/x86/Debug/Cat.Net.csproj.FileListAbsolute.txt deleted file mode 100644 index 53b7d06..0000000 --- a/obj/x86/Debug/Cat.Net.csproj.FileListAbsolute.txt +++ /dev/null @@ -1,5 +0,0 @@ -E:\work\csharp\Cat.Net\bin\Debug\Cat.dll -E:\work\csharp\Cat.Net\bin\Debug\Cat.pdb -E:\work\csharp\Cat.Net\obj\x86\Debug\ResolveAssemblyReference.cache -E:\work\csharp\Cat.Net\obj\x86\Debug\Cat.dll -E:\work\csharp\Cat.Net\obj\x86\Debug\Cat.pdb diff --git a/obj/x86/Debug/Cat.dll b/obj/x86/Debug/Cat.dll deleted file mode 100644 index e871f06..0000000 Binary files a/obj/x86/Debug/Cat.dll and /dev/null differ diff --git a/obj/x86/Debug/Cat.pdb b/obj/x86/Debug/Cat.pdb deleted file mode 100644 index c534f03..0000000 Binary files a/obj/x86/Debug/Cat.pdb and /dev/null differ diff --git a/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache deleted file mode 100644 index 9f12ff5..0000000 Binary files a/obj/x86/Debug/DesignTimeResolveAssemblyReferencesInput.cache and /dev/null differ