Fetch consumer count from RabbitMQ - c#

I am trying to fetch the total number of consumers for a particular queue in RabbitMQ. I wrote my code in C# using RabbitMQ client for .Net.
string user = ConfigurationManager.AppSettings["rmq_user"];
string pword = ConfigurationManager.AppSettings["rmq_pass"];
string port = ConfigurationManager.AppSettings["rmq_port"];
string host = new Uri(ConfigurationManager.AppSettings["rest_api_url"]).Host;
var factory = new ConnectionFactory();
factory.Uri = "amqp://" + user + ":" + pword + "#" + host + ":" + port;
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
var consumerCount = ((RabbitMQ.Client.Impl.ModelBase)(channel)).m_consumers;
}
}
I am getting var consumerCount = ((RabbitMQ.Client.Impl.ModelBase)(channel)).m_consumers; as 0. However I can see the consumers in the RabbitMQ web and I have made sure that the consumers do exist in that queue.
Is this the correct way to get the consumer count or I am doing something wrong? I know this can be done using RabbitMQ admin but I need to do it in C#.
Please let me know if I can give some more details.

It is not working as you have not specified the queue for which you want the consumers.
You can do it as follows:
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
var queueDeclareOK = channel.QueueDeclarePassive(QueueName);
var consumerCount = queueDeclareOK.ConsumerCount;
}
}

See IModal.ConsumerCount() on docs

In golang, there is a method called QueueInspect, it will return consumer count:
queue, err := channel.QueueInspect(queueName)
if err != nil {
return errors.New("fail to inspect queue " + queueName + "err: " + err.Error())
}
fmt.Println("consumer count is ", queue.Consumers)

Related

Appended strings in message body not being sent in email using SMTPClient() and StringBuilder()

First and foremost I am very new to C# and am sure most of my code could be cleaned up so please don't suggest it unless you are also offering help with my issue.
I am sending an email via SmtpClient(). I am trying to build the body of the email using strings which are returned from functions in loops. My issue is that the string for the body isn't building how I thought it should.
Currently, I am creating a new StringBuilder() with some default text in it. I am then running some functions and trying to add the results to the StringBuilder() object via StringBuilder.AppendLine().
Here is (some of) my code:
// Setup SMTP Client for sending mail updates
//-----------------------------------
String from_addr_text = "<removed>";
String to_addr_text = "<removed>";
String msg_subject = "Updates to USPTO searches";
StringBuilder msg_body = new StringBuilder("The following searches have received updated results:" + Environment.NewLine);
SmtpClient AlertMail = new SmtpClient
{
Port = 587,
Host = "<removed>",
EnableSsl = true,
Timeout = 10000,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new System.Net.NetworkCredential("<removed>", "<removed>")
};
MailMessage update = new MailMessage(from_addr_text, to_addr_text, msg_subject, msg_body.ToString())
{
BodyEncoding = UTF8Encoding.UTF8,
IsBodyHtml = false,
DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure
};
...
// Process data from api for Assignor
//-----------------------------------
bool isUpdated = false;
foreach (String url in searchesByAssignorUSPTO)
{
try
{
String longName = <removed>);
String name = <removed>;
String thisHash = await GetSearchData(url, name, "Assignor");
if (DoesHashExist(thisHash))
{
Debug.WriteLine(thisHash + " already exists. No update to " + name + " search.");
}
else
{
Debug.WriteLine(thisHash + " does not exist. There is an update to " + name + " search.");
isUpdated = true;
msg_body.AppendLine(name + " as " + "Assignor" + Environment.NewLine);
}
}
catch
{
Console.WriteLine("something is broken with ASSIGNOR search dummy!");
}
}
// Process data from api for Assignee
foreach (String url in searchesByAssigneeUSPTO)
{
try
{
String longName = <removed>;
String name = <removed>;
String thisHash = await GetSearchData(url, name, "Assignee");
if (DoesHashExist(thisHash))
{
Debug.WriteLine(thisHash + " already exists. No update to " + name + " search.");
}
else
{
Debug.WriteLine(thisHash + " does not exist. There is an update to " + name + " search.");
isUpdated = true;
msg_body.AppendLine(name + " as " + "Assignee" + Environment.NewLine);
}
}
catch
{
Console.WriteLine("something is broken with ASSIGNEE search dummy!");
}
}
// Send email is search results are updated
if (isUpdated)
{
AlertMail.Send(update);
Debug.WriteLine(msg_body.ToString());
}
When the program runs and there are results returned from the loops, msg_body is printed to the output window correctly but, when the email is received the body is only: "The following searches have received updated results:".
I have tried:
changing the value of isBodyHtml to true and used <br />
instead of Environment.NewLine.
adding \n to end of stringing and removing Environment.NewLine.
changing msg_body to type String and concatenating results to msg_body using =+.
using the Append() method instead of AppendLine().
Here is a snip of the output window:
Be sure to watch the assignment of variables in your code. When you assign msg_body to the update MailMessage object, it's only inputting the one line mentioned that is being returned in the email and doesn't include the information generated by the API.
Try moving the intialization of your SmtpClient and MailMessage variables to right before the if (isUpdated) block and you should be good to go.
per #tym32167, I needed to move the instantiation of MailMessage() to AFTER my loops and functions were completed. I was creating the object before the AppendLines() methods were called and therefore they weren't being included.

How can I get total number of devices and total number of messages send to azure IoT hub c#

we only have these two methods available for azure IoThub in c#.
Device device = await registryManager.GetDeviceAsync("deviceId");
and
device = await registryManager.GetDevicesAsync("max count");
but how to get all available device count or active device count and also a messages count using c#?
The values what you are interested are part of the Azure IoT Hub metrics. Basically you can obtained their:
using the REST API and here
Adding the diagnostic settings for Azure IoT Hub and selecting one of the following destination for AllMetrics:
to archiving in the event-driven storage. Using a subscriber such as an EventGridTrigger function with an input blob binding, the metrics can be queried within the function body.
or pushing the metrics to streaming pipe via an Event Hub and using a stream analytics job for querying the metrics data.
The number of devices can be retrieved by using a device query, e.g.:
SELECT COUNT() AS numberOfDevices FROM c
which returns something like this:
[
{
"numberOfDevices": 123
}
]
To retrieve the number of messages you need to connect to the Event Hub-compatible endpoint, connecting to each underlying partition and looking at each Partition Info (Last Sequence Number and Sequence Number). There is some data retention involved though, so unless you add more logic to this, you will get a number representing the count of messages currently present in the hub, not the total since the creation, not the total left to process.
Update: here's the code showing a couple of methods to get the number of devices:
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.Devices;
using Newtonsoft.Json;
namespace Test
{
class Program
{
static async Task Main()
{
string connString = "HostName=_______.azure-devices.net;SharedAccessKeyName=_______;SharedAccessKey=_______";
RegistryManager registry = RegistryManager.CreateFromConnectionString(connString);
// Method 1: using Device Twin
string queryString = "SELECT COUNT() AS numberOfDevices FROM devices";
IQuery query = registry.CreateQuery(queryString, 1);
string json = (await query.GetNextAsJsonAsync()).FirstOrDefault();
Dictionary<string, long> data = JsonConvert.DeserializeObject<Dictionary<string, long>>(json);
long count1 = data["numberOfDevices"];
// Method 2: using Device Registry
RegistryStatistics stats = await registry.GetRegistryStatisticsAsync();
long count2 = stats.TotalDeviceCount;
}
}
}
As of my knowledge,
There is no direct method to actually get the total number of devices. Alternatively what you could do is to create a List and whenever you add Devices using AddDeviceAsync you should push the object to the list.
Same with Total number of messages, you should create your own way to keep the value updated.
The following code should help.
static async Task startClient(string IoTHub, string IoTDevicePrefix, int deviceNumber, string commonKey, int maxMessages, int messageDelaySeconds)
{
allClientStarted++;
runningDevices++;
string connectionString = "HostName=" + IoTHub + ";DeviceId=" + IoTDevicePrefix + deviceNumber + ";SharedAccessKey=" + commonKey;
DeviceClient device = DeviceClient.CreateFromConnectionString(connectionString, Microsoft.Azure.Devices.Client.TransportType.Mqtt);
await device.OpenAsync();
Random rnd = new Random();
int mycounter = 1;
Console.WriteLine("Device " + IoTDevicePrefix + deviceNumber + " started");
while (mycounter <= maxMessages)
{
Thread.Sleep((messageDelaySeconds * 1000) + rnd.Next(1, 100));
string message = "{ \'loadTest\':\'True\', 'sequenceNumber': " + mycounter + ", \'SubmitTime\': \'" + DateTime.UtcNow + "\', \'randomValue\':" + rnd.Next(1, 4096 * 4096) + " }";
Microsoft.Azure.Devices.Client.Message IoTMessage = new Microsoft.Azure.Devices.Client.Message(Encoding.UTF8.GetBytes(message));
await device.SendEventAsync(IoTMessage);
totalMessageSent++;
mycounter++;
}
await device.CloseAsync();
Console.WriteLine("Device " + IoTDevicePrefix + deviceNumber + " ended");
runningDevices--;
}
static void createDevices(int number)
{
for (int i = 1; i <= number; i++)
{
var registryManager = RegistryManager.CreateFromConnectionString(iotHubConnectionString);
Device mydevice = new Device(IoTDevicePrefix + i.ToString());
mydevice.Authentication = new AuthenticationMechanism();
mydevice.Authentication.SymmetricKey.PrimaryKey = commonKey;
mydevice.Authentication.SymmetricKey.SecondaryKey = commonKey;
try
{
registryManager.AddDeviceAsync(mydevice).Wait();
Console.WriteLine("Adding device: " + IoTDevicePrefix + i.ToString());
}
catch (Exception er)
{
Console.WriteLine(" Error adding device: " + IoTDevicePrefix + i.ToString() + " error: " + er.InnerException.Message);
}
}
}

Would like code improvement on C# TCP listener to SQL Server database app

I have built a C# console app that accepts TCP connections from GPS reporting devices I have. I built this app to collect that data and dump it into a SQL Server table.
Currently, I have the application working, but it has a bug I can't seem to figure out. As the GPS devices make connections, one out of random 1-10 successful connections give me an index out of range exception.
When I dump the raw data it does not look like something the device is sending me. Would any of you happen to know what is causing this? Also, once I get this application working correctly, it could be receiving up to 3-5k connections a minute, do you think this code could handle this?
This is the error I receive every so often, with the dump of misc data:
Image of error
This is my code:
namespace GPS2DB
{
class Program
{
static void Main(string[] args)
{
try
{
IPAddress ipAddress = IPAddress.Parse("10.71.150.253");
Console.WriteLine("Waiting for Tracker Connections...");
TcpListener listener = new TcpListener(ipAddress, 10000);
listener.Start();
while (true)
{
Socket client = listener.AcceptSocket();
Console.WriteLine("Connection accepted.");
var childSocketThread = new Thread(() =>
{
byte[] data = new byte[1024];
int size = client.Receive(data);
string gpsData = "";
for (int i = 0; i < size; i++)
{
Console.Write(Convert.ToChar(data[i]));
gpsData = gpsData + Convert.ToChar(data[i]);
}
string txt = gpsData;
string txt2 = (txt.Trim(new Char[] { '$', '#' }));
String[] values = txt2.Split(',');
//Console.WriteLine(txt2);
/*
Console.WriteLine("Unit ID: " + values[0]);
Console.WriteLine("Event Code: " + values[1]);
Console.WriteLine("UTC Date: " + values[2]);
Console.WriteLine("UTC Time: " + values[3]);
Console.WriteLine("Lat: " + values[4]);
Console.WriteLine("Long: " + values[5]);
Console.WriteLine("Speed: " + values[7]);
Console.WriteLine("Heading: " + values[11]);
Console.WriteLine("V+: " + values[16]);
Console.WriteLine("Cell Strength: " + values[17]);
Console.WriteLine("GPS Status: " + values[18]);
Console.WriteLine("Fuel Level: " + values[20]);
*/
//dump 2 database
string connectionString = "Data Source=DVT501;Initial Catalog=VehicleTracking;Persist Security Info=True;User ID=TABLE;Password=PASS";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("INSERT INTO Data_Dump (uid, eventCode, utcDate, utcTime, lat, long, speed, heading, voltage, cellStrength, gpsStatus, fuelLevel) VALUES (#uid, #eventCode, #utcDate, #utcTime, #lat, #long, #speed, #heading, #voltage, #cellStrength, #gpsStatus, #fuelLevel)");
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = connection;
try
{
cmd.Parameters.AddWithValue("#uid", values[0]);
cmd.Parameters.AddWithValue("#eventCode", values[1]);
cmd.Parameters.AddWithValue("#utcDate", values[2]);
cmd.Parameters.AddWithValue("#utcTime", values[3]);
cmd.Parameters.AddWithValue("#lat", values[4]);
cmd.Parameters.AddWithValue("#long", values[5]);
cmd.Parameters.AddWithValue("#speed", values[7]);
cmd.Parameters.AddWithValue("#heading", values[11]);
cmd.Parameters.AddWithValue("#voltage", values[16]);
cmd.Parameters.AddWithValue("#cellStrength", values[17]);
cmd.Parameters.AddWithValue("#gpsStatus", values[18]);
cmd.Parameters.AddWithValue("#fuelLevel", values[20]);
connection.Open();
cmd.ExecuteNonQuery();
}
catch (System.IndexOutOfRangeException e)
{
Console.WriteLine("IndexOutOfRangeException caught" + e);
Console.WriteLine(txt);
}
}
//end dump
Console.WriteLine();
client.Close();
});
childSocketThread.Start();
}
listener.Stop();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.StackTrace);
Console.ReadLine();
}
}
}
}
The error is with the incoming data, it's either a gps device that's configured to send data differently or some random tcp event. Check the port number you're using in a google search and make sure it's not reserved for something else.
This code will definitely not handle that many connections, you iterate through a byte array and convert one character at a time (use System.Text.Encoding.ASCII.GetString(byte[]) instead), you open and close a connection to the sql server within the receive block and so on. In order to handle that kind of activity you need to just read the data and put it in a bus or temp storage to be bulk processed.
You are assuming that you will read one message at a time. TCP provides a boundaryless stream of bytes. You can very well read a partial message or multiple messages.
How to deal with that depends on the format of the stream. If it is line based StreamReader.ReadLine() is a great solution.

Using the Splunk SDK for C#, why is oneshot search ignoring the set time range?

I have an odd problem with setting time range for oneshot search. I set time range for my oneshot search, but results are just first found on server matching query. It seems like oneshot is just ignoring time range.
I've read:
How to run searches and jobs using the Splunk SDK for C# -
http://dev.splunk.com/view/csharp-sdk/SP-CAAAEQG
Service.SearchOneShotAsync Method -
http://docs.splunk.com/DocumentationStatic/CshrpSDK/2.1.1/Splunk.Client/html/a5323948-7506-ad15-6f04-7a95b70e616d.htm
JobArgs Class -
http://docs.splunk.com/DocumentationStatic/CshrpSDK/2.1.1/Splunk.Client/html/7dc4e71d-1ed7-4eb1-5a10-183d7663da26.htm
Time modifiers for search -
http://docs.splunk.com/Documentation/Splunk/6.0.3/SearchReference/SearchTimeModifiers
but after hours of tests and experiments - nothing.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var connectArgs = new ServiceArgs
{
Host = "myip",
Port = 8089,
Scheme = "https"
};
Splunk.Service service = new Splunk.Service(connectArgs);
service.Login("login", "password");
var oneshotSearchArgs = new Splunk.Client.JobArgs();
oneshotSearchArgs.EarliestTime = "2015-08-23 13:00";//textBoxOD.Text + "T" + textBoxODG.Text + ":00.000";
oneshotSearchArgs.LatestTime = "2015-08-23 14:00";//textBoxDO.Text + "T" + textBoxDOG.Text + ":00.000";
String oneshotSearchQuery = "search query *" + textBox1.text + "* | head 500";
var outArgs = new JobResultsArgs
{
OutputMode = JobResultsArgs.OutputModeEnum.Xml,
Count = 0,
};
try
{
using (var stream = service.Oneshot(oneshotSearchQuery, outArgs))
{
using (var rr = new ResultsReaderXml(stream))
{
string raw = "_raw";
foreach (var #event in rr)
{
wynik += "EVENT:" + Environment.NewLine;
foreach (string key in #event.Keys)
{
if (key.Contains(raw))
{
wynik += " " + key + " -> " + #event[key] + Environment.NewLine + Environment.NewLine;
}
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
Sorry for being so late with an answer. I landed into the same issue.
The reason that your OneShot search ignores the time range is because it does not take one. (I did not come across any documentation to do so)
To overcome this issue, I tried the 2.X SDK for C#. It fixed the issue.
You can use the 2.X version in 3 steps:
Setting up Service parameters. (host, port etc.)
Authenticating the Service.
Setting up parameters for the OneShot job and executing it.
You can find the NuGet package "Splunk PCL Client for .Net" in NuGet library here.
Here is a sample code:
// Setting up Service parameters
Service _splunkService = new Service(Scheme.Https, "your-api-or-ip", 8089);
// Authenticating
await _splunkService.LogOnAsync("username", "password");
// Setting up parameters for the OneShot job and executing it
var query = "your search query";
var oneShot = new JobArgs();
oneShot.EarliestTime = DateTime.Now.AddMinutes(-2).Date.ToString("yyyy-MM-dd") + "T" + DateTime.Now.AddMinutes(-2).TimeOfDay; //"2015-09-12T12:00:00.000-07:00";
oneShot.LatestTime = "your latest time";
using (var stream = await _splunkService.SearchOneShotAsync(query, 0, oneShot))
{
try
{
foreach (var result in stream)
{
var rawValue = Convert.ToString(result.GetValue("_raw"));
if (rawValue != null)
{
// do something.
}
}
}
}
Make sure the 'await' parts go inside an async method.

WMI throwing Exception "Invalid Query" on second attempt to query the same server

I have a following code, almost all the time this code works for most of my server, but for some specific servers, it just fails on second part of query. this code query the SQL Server Service First and in second part it queries the SQL Sevrer Agent Service.
I have tried all possible combination of creating another Scope and Query Object, but somehow the server I am trying to query does not return seccond part, looks like after the scope is connected and first query is executed, second part is blocked by something on server..! Any help on this one is appreciated.. almost 99% of servers works fine and returns desire results, but just 2 or 3 servers fails for second part..
If this is WMI issue on the server it self..? is there any other way to achieve these status..? like IPC or Sockets..? please help..!
Hash.
try
{
agentserviceName = "SQLSERVERAGENT";
serviceName = "MSSQLSERVER";
query = new System.Management.SelectQuery(string.Format("select name, startname, State, StartMode from Win32_Service where name = '{0}'", serviceName));
ManagementScope scope = new ManagementScope("\\\\" + srvName + "\\root\\cimv2");
//ManagementScope scope = new ManagementScope("\\\\ST0176V\\root\\cimv2");
scope.Connect();
System.Management.ManagementObjectSearcher searcher = new System.Management.ManagementObjectSearcher(scope, query);
// MessageBox.Show((String)dgv_ChangeSvcAccount.Rows[i].Cells[1].Value.ToString());
foreach (ManagementObject service in searcher.Get())
{
dgv_ChangeSvcAccount.Rows[i].Cells[4].Value = service["startname"];
dgv_ChangeSvcAccount.Rows[i].Cells[4].Tag = serviceName;
dgv_ChangeSvcAccount.Rows[i].Cells[5].Value = "Currently : " + service["State"] + " - Set As : " + service["StartMode"];
}
if (searcher.Get().Count == 0)
{
dgv_ChangeSvcAccount.Rows[i].Cells[4].Value = "NO SQL Service Found";
}
searcher.Dispose();
ManagementScope scope2 = new ManagementScope("\\\\" + srvName + "\\root\\cimv2");
// ObjectQuery query2 = new ObjectQuery("SELECT * FROM Win32_Service WHERE NAME LIKE '" + serviceName.ToString().ToUpper() + "'");
System.Management.SelectQuery query2 = new System.Management.SelectQuery(string.Format("select name, startname, State, StartMode from Win32_Service where name like '{0}'", agentserviceName));
System.Management.ManagementObjectSearcher searcher1 = new System.Management.ManagementObjectSearcher(scope2, query2);
foreach (ManagementObject service in searcher1.Get()) // <---- this line throws exception for invalid query, and it is always 2 servers which does that, rest of servers returns proper results. the servers which throws this Invlid Query exceptions are Windows 2000 Server with SP4.
{
dgv_ChangeSvcAccount.Rows[i].Cells[6].Value = service["startname"];
dgv_ChangeSvcAccount.Rows[i].Cells[6].Tag = agentserviceName;
dgv_ChangeSvcAccount.Rows[i].Cells[7].Value = "Currently : " + service["State"] + " - Set As : " + service["StartMode"];
}
searcher1.Dispose();
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
Since, as we've been discussing in the comments, we're thinking it might have to do with having multiple active ManagementScope objects, try changing the first half of your code to this:
string agentserviceName = "SQLSERVERAGENT";
string serviceName = "MSSQLSERVER";
// Let the SelectQuery class build our WQL query text...
string className = "Win32_Service";
string condition = string.Format("Name = '{0}'", serviceName);
string[] selectedProperties = new string[] { "Name", "StartName", "State", "StartMode" };
SelectQuery query = new SelectQuery(className, condition, selectedProperties);
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(query))
{
searcher.Scope = new ManagementScope("\\\\" + srvName + "\\root\\cimv2");
foreach (ManagementObject service in searcher.Get())
{
dgv_ChangeSvcAccount.Rows[i].Cells[4].Value = service["startname"];
dgv_ChangeSvcAccount.Rows[i].Cells[4].Tag = serviceName;
dgv_ChangeSvcAccount.Rows[i].Cells[5].Value = "Currently : " + service["State"] + " - Set As : " + service["StartMode"];
}
if (searcher.Get().Count == 0)
{
dgv_ChangeSvcAccount.Rows[i].Cells[4].Value = "NO SQL Service Found";
}
}
// Second query goes here...
That will dispose the ManagementObjectSearcher for the first query when it's done being used, and also ensure that it holds the only reference to the ManagementScope for the remote server.

Categories

Resources