CPU Usage of an instance with Cloudwatch API - c#

How do i get the CPU usage of an instance in c#?
I've read Amazon EC2 - how to get available ram and cpu usage via AWS API? already, but i can't get it working.
NameValueCollection appConfig = ConfigurationManager.AppSettings;
var client = AWSClientFactory.CreateAmazonCloudWatchClient(
appConfig["AWSAccessKey"],
appConfig["AWSSecretKey"]
);
var dimension = new Dimension
{
Name = "InstanceId",
Value = "<i-ad20b4db>",
};
var request = new GetMetricStatisticsRequest();
request.MetricName = "CPUUtilization";
request.Period = 60;
request.Statistics.Add("Maximum");
request.Dimensions.Add(dimension);
request.Namespace = "AWS/EC2";
request.Unit = "Percent";
var currentTime = DateTime.UtcNow;
var startTime = currentTime.AddSeconds(-5);
string currentTimeString= currentTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
string startTimeString= startTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
request.StartTime = Convert.ToDateTime( startTimeString);
request.EndTime = Convert.ToDateTime(currentTimeString);
var response = client.GetMetricStatistics(request);
if ( response.GetMetricStatisticsResult.Datapoints.Count > 0)
{
var dataPoint = response.GetMetricStatisticsResult.Datapoints[0];
Console.WriteLine( "Instance: {0} CPU Max load: {1}", dimension.Value, dataPoint.Maximum);
}

Here's a simple proof of concept for showing the CPU Utilization during the last two days. I think there will be a datapoint like every half an hour, but you can easily change by changing the value of the Period property in the GetMetricStatisticsRequest object.
AmazonCloudWatch cw = AWSClientFactory.CreateAmazonCloudWatchClient(accessKey, secretKey, new AmazonCloudWatchConfig().WithServiceURL("https://eu-west-1.monitoring.amazonaws.com"));
DataTable data = new DataTable();
try
{
Dimension dim = new Dimension() { Name = "InstanceId", Value = GetInstanceName(amazonInstance) };
System.Collections.Generic.List<Dimension> dimensions = new List<Dimension>() { dim };
string startTime = startTime = DateTimeOffset.Parse(DateTime.Now.AddDays(-2).ToString()).ToUniversalTime().ToString("s"); // "2010-09-29T11:00:00+01:00";
GetMetricStatisticsRequest reg = new GetMetricStatisticsRequest()
{
MeasureName = "CPUUtilization",
Period = 1800
Statistics = new System.Collections.Generic.List<string>() { "Average" },
Dimensions = dimensions,
Namespace = "AWS/EC2",
EndTime = DateTime.Now.ToUniversalTime().ToString("s"), //has to be in this format: 2010-09-29T14:00:00+01:00;
StartTime = startTime
};
var points = cw.GetMetricStatistics(reg).GetMetricStatisticsResult.Datapoints.OrderBy(p => p.Timestamp);
data.Columns.Add("Average");
data.Columns.Add("TimeStamp");
foreach (var p in points)
{
DataRow row = data.NewRow();
row["Average"] = Math.Round(p.Average, 0);
row["TimeStamp"] = DateTimeOffset.Parse(p.Timestamp).LocalDateTime.ToString("yyyy-MM-dd HH:mm");
data.Rows.Add(row);
}
}
catch (AmazonCloudWatchException ex)
{
if (ex.ErrorCode.Equals("OptInRequired"))
throw new Exception("You are not signed in for Amazon EC2.");
else
throw;
}

This is my final code which works for me.
I have added new user in the IAM aws management console then i have Attached CloudWatchfullacess Policy to new user then i have used this user Accesskey & secret key in this Code.
var cw =AWSClientFactory.CreateAmazonCloudWatchClient("AccessKey","secretkey",Amazon.RegionEndpoint.USWest2);
DataTable data = new DataTable();
try
{
Dimension dim = new Dimension() { Name = "InstanceId", Value = "InstanceId of you EC2 Server" };
System.Collections.Generic.List<Dimension> dimensions = new List<Dimension>() { dim };
string startTime1 = DateTimeOffset.Parse(DateTime.Now.AddMinutes(-60).ToString()).ToUniversalTime().ToString("s");
GetMetricStatisticsRequest reg = new GetMetricStatisticsRequest()
{
MetricName = "CPUUtilization",
Period = 60,
Statistics = new System.Collections.Generic.List<string>() { "Average","Minimum","Maximum" },
Dimensions = dimensions,
Namespace = "AWS/EC2",
EndTime = DateTime.Now, //Convert.ToDateTime(DateTime.Now.ToUniversalTime().ToString("s")), //has to be in this format: 2010-09-29T14:00:00+01:00;
StartTime = DateTime.Now.AddHours(Convert.ToInt32(-15)),// Convert.ToDateTime(startTime1),
};
var points = cw.GetMetricStatistics(reg).GetMetricStatisticsResult.Datapoints.OrderBy(p => p.Timestamp);
data.Columns.Add("Average");
data.Columns.Add("TimeStamp");
foreach (var p in points)
{
DataRow row = data.NewRow();
row["Average"] = Math.Round(p.Average, 0);
row["TimeStamp"] = p.Timestamp; //DateTimeOffset.Parse(Convert.ToDateTime(p.Timestamp)).LocalDateTime.ToString("yyyy-MM-dd HH:mm");
data.Rows.Add(row);
}
dataGridView1.DataSource = data;
}
catch (AmazonCloudWatchException ex)
{
if (ex.ErrorCode.Equals("OptInRequired"))
throw new Exception("You are not signed in for Amazon EC2.");
else
throw;
}

Pleas also note that when you want to get CPU usage or any other type of metric, you should be wary of the time-stamp you include in the request. This is because it can take more than 48 hours for data to become available in CloudWatch (according to Amazon).
That is why I personally try to retrieve data from about 3-4 days ago as sometimes CloudWatch will not return any data even if the request and the code are all correct as it does not have any data to publish from the previous day or two.
For more information check this URL and scroll down to StartTime: http://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetMetricStatistics.html

Related

Google Analytics get daily data from last 30 days

I'm trying to create a report showing daily conversions from the last 30 days with google analytics data api. This is using the dotnet client library Google.Analytics.Data.V1Beta.
However I'm only getting back about 5 conversion values, the last value seems to be reflecting total conversions of all time, ideally I'd like a running update of how many conversions per day so I can plot it to a line chart.
I'm planning to change this to weekly over the course of the past X months once I have the previous issue sorted out.
I'm essentially trying to recreate the chart on the google analytics dashboard:
What am I missing?
public async Task<RunReportResponse> RunReport(string propertyId = "xxxx")
{
BetaAnalyticsDataClient client = BetaAnalyticsDataClient.Create();
FilterExpression hostnameFilter = new();
hostnameFilter.Filter = new();
hostnameFilter.Filter.InListFilter = new();
hostnameFilter.Filter.InListFilter.Values.Add("xxxx");
hostnameFilter.Filter.FieldName = "hostName";
CohortSpec cohort = new();
cohort.Cohorts.Add(new Cohort
{
Dimension = "firstSessionDate",
DateRange = new DateRange()
{
StartDate = DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd"),
EndDate = DateTime.Now.ToString("yyyy-MM-dd")
},
});
cohort.CohortsRange = new CohortsRange
{
EndOffset = 5,
Granularity = CohortsRange.Types.Granularity.Daily
};
// Initialize request argument(s)
RunReportRequest request = new()
{
Property = "properties/" + propertyId,
Dimensions = {new Dimension { Name = "cohort" }, new Dimension { Name = "cohortNthDay" } },
Metrics = { new Metric { Name = "conversions" }, },
DimensionFilter = hostnameFilter,
CohortSpec = cohort,
};
// Make the request
var response = await client.RunReportAsync(request);
return response;
}
}

Is Universal Analytics C# SDK compatible with GA4?

I am using Google.Apis.AnalyticsReporting.v4 library for old google analytics views. How do I convert this code to GA4? I can't find a line about switching View Id to something else in code.
I have checked this post "How do I get view id in GA4", but my properties already exist and I don't see option to modify them after creation.
using (var svc = new AnalyticsReportingService(authInitializer.CreateInitializer()))
{
var dateRange = new DateRange
{
StartDate = analyticsParams.From.ToString("yyyy-MM-dd"),
EndDate = analyticsParams.To.ToString("yyyy-MM-dd")
};
var sessions = new Metric
{
Expression = "ga:sessions",
Alias = "Sessions"
};
var date = new Dimension { Name = "ga:date" };
var reportRequest = new ReportRequest
{
DateRanges = new List<DateRange> { dateRange },
Dimensions = new List<Dimension> { date },
Metrics = new List<Metric> { sessions },
ViewId = analyticsParams.ViewId, // <------------------------- My view id
};
var getReportsRequest = new GetReportsRequest
{
ReportRequests = new List<ReportRequest> { reportRequest }
};
var batchRequest = svc.Reports.BatchGet(getReportsRequest);
var response = batchRequest.Execute();
var reports = response.Reports.First();
return reports.Data.Rows.Select(x => new DataEntry()
{
Date = DateTime.ParseExact(x.Dimensions[0], "yyyyMMdd", CultureInfo.InvariantCulture),
Value = int.Parse(x.Metrics[0].Values[0]),
}).ToList();
}
You need to use the Google Analytics Data API V1 (currently in alpha) in order to access your GA4 properties. Here is a quick start sample for .NET which seems similar to what you are trying to do.
using Google.Analytics.Data.V1Alpha;
using System;
namespace AnalyticsSamples
{
class QuickStart
{
static void SampleRunReport(string propertyId)
{
// Using a default constructor instructs the client to use the credentials
// specified in GOOGLE_APPLICATION_CREDENTIALS environment variable.
AlphaAnalyticsDataClient client = AlphaAnalyticsDataClient.Create();
// Initialize request argument(s)
RunReportRequest request = new RunReportRequest
{
Entity = new Entity{ PropertyId = propertyId },
Dimensions = { new Dimension{ Name="city"}, },
Metrics = { new Metric{ Name="activeUsers"}, },
DateRanges = { new DateRange{ StartDate="2020-03-31", EndDate="today"}, },
};
// Make the request
RunReportResponse response = client.RunReport(request);
Console.WriteLine("Report result:");
foreach( Row row in response.Rows )
{
Console.WriteLine("{0}, {1}", row.DimensionValues[0].Value, row.MetricValues[0].Value);
}
}
static int Main(string[] args)
{
if (args.Length == 0 || args.Length > 2)
{
Console.WriteLine("Arguments: <GA4 property ID>");
Console.WriteLine("A GA4 property id parameter is required to make a query to the Google Analytics Data API.");
return 1;
}
string propertyId = args[0];
SampleRunReport(propertyId);
return 0;
}
}
}
Currently there aren't API available for GA4 Property. Furthermore GA4 does not provide Views, you have to use BigQuery to get data programmatically.

Rally Api - How do I page GetByReference results

I've got some code that looks something like this.
var userStory = restApi.GetByReference (userStoryRef, "Name", "FormattedID");
for (int i = 0; i < (int) userStory["TotalResultCount"]; i++)
{
var name = userStory["Results"][i]["Name"];
...
Of course this fails if the GetByReference has more than 20 results (i.e. TotalResultCount > 20) since the default page size is 20.
So I need to page this but I can't work out how you set the page size, or request a second page from GetByReference.
I tried adding ?pagesize=100 to the reference but it doesn't appear to affect the result set.
e.g.
var userStory = restApi.GetByReference (userStoryRef + "?pagesize=100", "Name", "FormattedID");
I also tried giving up on this altogether and re-phrasing it as a query (which I do know how to page.)
e.g.
var request = new Request("HierarchicalRequirement")
{
Fetch = new List<string>()
{
"Name", "FormattedID"
}, Query = new Query("Parent.FormattedID", Query.Operator.Equals, featureId)
};
var result = myRestApi.Query(request);
But this query doesn't work for me either (featureId is a valid formatted id with associated User Stories). But that query returns no results.
(I appreciate that's a different question altogether - happy to get either working but understanding both would be fantastic!)
Grateful as ever for any help.
See code below. Notice storiesRequest.Limit = 1000 When this number is above default 20, it defaults to max 200, so there is no need to set storiesRequest.PageSize to 200
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rally.RestApi;
using Rally.RestApi.Response;
using Rally.RestApi.Json;
namespace GetByRefExample
{
class Program
{
static void Main(string[] args)
{
RallyRestApi restApi = new RallyRestApi(webServiceVersion: "v2.0");
String apiKey = "_abc123";
restApi.Authenticate(apiKey, "https://rally1.rallydev.com", allowSSO: false);
String workspaceRef = "/workspace/123";
String projectRef = "/project/456";
Request request = new Request("PortfolioItem/Feature");
request.Fetch = new List<string>() { "Name", "FormattedID" };
request.Query = new Query("FormattedID", Query.Operator.Equals, "F2356");
QueryResult result = restApi.Query(request);
String featureRef = result.Results.First()._ref;
Console.WriteLine("found" + featureRef);
//create stories
try
{
for (int i = 1; i <= 25; i++)
{
DynamicJsonObject story = new DynamicJsonObject();
story["Name"] = "story " + i;
story["PlanEstimate"] = new Random().Next(2,10);
story["PortfolioItem"] = featureRef;
story["Project"] = projectRef;
CreateResult createResult = restApi.Create(workspaceRef, "HierarchicalRequirement", story);
story = restApi.GetByReference(createResult.Reference, "FormattedID");
Console.WriteLine("creating..." + story["FormattedID"]);
}
//read stories
DynamicJsonObject feature = restApi.GetByReference(featureRef, "UserStories");
Request storiesRequest = new Request(feature["UserStories"]);
storiesRequest.Fetch = new List<string>()
{
"FormattedID",
"PlanEstimate"
};
storiesRequest.Limit = 1000;
QueryResult storiesResult = restApi.Query(storiesRequest);
int storyCount = 0;
foreach (var userStory in storiesResult.Results)
{
Console.WriteLine(userStory["FormattedID"] + " " + userStory["PlanEstimate"]);
storyCount++;
}
Console.WriteLine(storyCount);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
}

How do I use AWS SDK for .Net to create an image to an instance I have? (AMI)

I have an Amazon EC2 instance and I need to be able to create an AMI (image) from it programmatically. I'm trying the following:
CreateImageRequest rq = new CreateImageRequest();
rq.InstanceId = myInstanceID;
rq.Name = instance.KeyName;
rq.Description = "stam";
rq.NoReboot = true;
IAmazonEC2 ec2;
AmazonEC2Config ec2conf = new AmazonEC2Config();
ec2 = AWSClientFactory.CreateAmazonEC2Client(ec2conf);
// CreateImageResponse imageResp;
Amazon.EC2.Model.CreateImageResponse imageResp = null;
try
{
imageResp = ec2.CreateImage(rq);
}
catch (AmazonServiceException ase)
{
MessageBox.Show(ase.Message);
}
The result is always an AmazonServiceException saying that there is a NameResolutionFailure.
How do I overcome this? I tried different possible "name" possibilities but cannot find the right one.
string amiID = ConfigurationManager.AppSettings[AmazonConstants.AwsImageId];
string keyPairName = ConfigurationManager.AppSettings[AmazonConstants.AwsKeyPair];
List<string> groups = new List<string>() { ConfigurationManager.AppSettings[AmazonConstants.AwsSecurityGroupId] };
var launchRequest = new RunInstancesRequest()
{
ImageId = amiID,
InstanceType = ConfigurationManager.AppSettings[AmazonConstants.AwsInstanceType],
MinCount = 1,
MaxCount = 1,
KeyName = keyPairName,
SecurityGroupIds = groups,
SubnetId = ConfigurationManager.AppSettings[AmazonConstants.AwsSubnetId]
};
RunInstancesResponse runInstancesResponse = amazonEc2client.RunInstances(launchRequest);
RunInstancesResult runInstancesResult = runInstancesResponse.RunInstancesResult;
Reservation reservation = runInstancesResult.Reservation;
Problem eventually solved!
it turned out thyat some codelines were doing things which were already done already and removing this part:
IAmazonEC2 ec2;
AmazonEC2Config ec2conf = new AmazonEC2Config();
ec2 = AWSClientFactory.CreateAmazonEC2Client(ec2conf);
// CreateImageResponse imageResp;
Amazon.EC2.Model.CreateImageResponse imageResp = null;
Made things clearer and no wrong repetitions happened! Now it works!

Getting the wrong event from google calendar api

Here is my current code:
Service = new CalendarService("googleid.apps.googleusercontent.com");
Service.setUserCredentials("calenderusername#gmail.com", "passwordforaccount");
var calendarquery = new EventQuery
{
Uri =new Uri("https://www.google.com/calendar/feeds/calenderusername#gmail.com/private/full"),
StartTime = DateTime.Now,
NumberToRetrieve = 1,
SortOrder = CalendarSortOrder.#ascending
};
var feedItem = Service.Query(calendarquery).Entries.FirstOrDefault() as EventEntry;
var times = new Google.GData.Extensions.When();
times = feedItem.Times[0];
var item = new CalendarEvent
{
Description = feedItem.Content.Content,
EventDateStart = times.StartTime,
Title = feedItem.Title.Text,
EventDateEnd = times.EndTime,
URL = feedItem.Links.FirstOrDefault().HRef.Content
};
However, i get the item listed out:
EventStartDate: {10.02.2014 11:00:00}
EventEndDate: {10.02.2014 23:30:00}
But i know there is an event today(07.02.2014). Anyone have any idea what im doing wrong?
I'm confused wether to use startDate or startTime in my calendarQuery.

Categories