Skip to content

Commit

Permalink
Adding better support for serverless functions and sample projects to…
Browse files Browse the repository at this point in the history
… show how to use them (#243)

* Adding better support for serverless functions and sample projects to show how to use them

* Some pr feedback.

* Change name to ProcessQueueDeferred. Couple more lambda sample updates.

* Minor

* Change local server port from 50000 to 5000

Co-authored-by: Blake Niemyjski <[email protected]>
  • Loading branch information
ejsmith and niemyjski authored Jan 8, 2021
1 parent cfc0dee commit 70525fc
Show file tree
Hide file tree
Showing 36 changed files with 612 additions and 14 deletions.
21 changes: 21 additions & 0 deletions Exceptionless.Net.sln
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Exceptionless.SampleWpf", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Exceptionless.Extensions.Hosting", "src\Platforms\Exceptionless.Extensions.Hosting\Exceptionless.Extensions.Hosting.csproj", "{A5589072-EC59-4A6A-B78D-5D2ABB36DB1B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Exceptionless.SampleHosting", "samples\Exceptionless.SampleHosting\Exceptionless.SampleHosting.csproj", "{693ED127-0124-4697-8369-700717615E85}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Exceptionless.SampleLambda", "samples\Exceptionless.SampleLambda\Exceptionless.SampleLambda.csproj", "{4B26BF7F-85FB-4B41-BF93-661E83A4EDD7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Exceptionless.SampleLambdaAspNetCore", "samples\Exceptionless.SampleLambdaAspNetCore\Exceptionless.SampleLambdaAspNetCore.csproj", "{D9987952-B891-48B4-AA93-59AA39F33FC4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -174,6 +180,18 @@ Global
{A5589072-EC59-4A6A-B78D-5D2ABB36DB1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5589072-EC59-4A6A-B78D-5D2ABB36DB1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5589072-EC59-4A6A-B78D-5D2ABB36DB1B}.Release|Any CPU.Build.0 = Release|Any CPU
{693ED127-0124-4697-8369-700717615E85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{693ED127-0124-4697-8369-700717615E85}.Debug|Any CPU.Build.0 = Debug|Any CPU
{693ED127-0124-4697-8369-700717615E85}.Release|Any CPU.ActiveCfg = Release|Any CPU
{693ED127-0124-4697-8369-700717615E85}.Release|Any CPU.Build.0 = Release|Any CPU
{4B26BF7F-85FB-4B41-BF93-661E83A4EDD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4B26BF7F-85FB-4B41-BF93-661E83A4EDD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4B26BF7F-85FB-4B41-BF93-661E83A4EDD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4B26BF7F-85FB-4B41-BF93-661E83A4EDD7}.Release|Any CPU.Build.0 = Release|Any CPU
{D9987952-B891-48B4-AA93-59AA39F33FC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D9987952-B891-48B4-AA93-59AA39F33FC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D9987952-B891-48B4-AA93-59AA39F33FC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D9987952-B891-48B4-AA93-59AA39F33FC4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -201,6 +219,9 @@ Global
{E1D077DE-C62E-4137-B609-3E9845C8A027} = {2CEE12C6-3840-4C01-A952-D3026B0A662A}
{AD95A70D-18DB-414E-9F6C-1B13B4FBA56E} = {2CEE12C6-3840-4C01-A952-D3026B0A662A}
{A5589072-EC59-4A6A-B78D-5D2ABB36DB1B} = {D363E15F-621D-40E4-8C96-DEE41A7070FF}
{693ED127-0124-4697-8369-700717615E85} = {2CEE12C6-3840-4C01-A952-D3026B0A662A}
{4B26BF7F-85FB-4B41-BF93-661E83A4EDD7} = {2CEE12C6-3840-4C01-A952-D3026B0A662A}
{D9987952-B891-48B4-AA93-59AA39F33FC4} = {2CEE12C6-3840-4C01-A952-D3026B0A662A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EBB2CC85-FF87-431B-865F-2F110B2A10E6}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Exceptionless\Exceptionless.csproj" />
<ProjectReference Include="..\..\src\Platforms\Exceptionless.AspNetCore\Exceptionless.AspNetCore.csproj" />
<ProjectReference Include="..\..\src\Platforms\Exceptionless.Extensions.Hosting\Exceptionless.Extensions.Hosting.csproj" />
<ProjectReference Include="..\..\src\Platforms\Exceptionless.Extensions.Logging\Exceptionless.Extensions.Logging.csproj" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion samples/Exceptionless.SampleAspNetCore/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"Exceptionless": {
"ApiKey": "LhhP1C9gijpSKCslHHCvwdSIz298twx271n1l6xw",
"ServerUrl": "http://localhost:50000",
"ServerUrl": "http://localhost:5000",
"DefaultData": {
"JSON_OBJECT": "{ \"Name\": \"Blake\" }",
"Boolean": true,
Expand Down
2 changes: 1 addition & 1 deletion samples/Exceptionless.SampleConsole/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
using LogLevel = Exceptionless.Logging.LogLevel;

// example of setting an attribute value in config.
[assembly: Exceptionless("LhhP1C9gijpSKCslHHCvwdSIz298twx271n1l6xw", ServerUrl = "http://localhost:50000")]
[assembly: Exceptionless("LhhP1C9gijpSKCslHHCvwdSIz298twx271n1l6xw", ServerUrl = "http://localhost:5000")]
[assembly: ExceptionlessSetting("EnableWelcomeMessage", "True")]

namespace Exceptionless.SampleConsole {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Platforms\Exceptionless.Extensions.Hosting\Exceptionless.Extensions.Hosting.csproj" />
<ProjectReference Include="..\..\src\Platforms\Exceptionless.Extensions.Logging\Exceptionless.Extensions.Logging.csproj" />
</ItemGroup>
</Project>
74 changes: 74 additions & 0 deletions samples/Exceptionless.SampleHosting/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace Exceptionless.SampleHosting {
public class Program {
public static void Main(string[] args) {
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(builder => {
// By default sends warning and error log messages to Exceptionless.
// Log levels can be controlled remotely per log source from the Exceptionless app in near real-time.
builder.AddExceptionless();
})
.UseExceptionless() // listens for host shutdown and
.ConfigureServices(services => {
// Reads settings from IConfiguration then adds additional configuration from this lambda.
// This also configures ExceptionlessClient.Default
services.AddExceptionless(c => c.DefaultData["Startup"] = "heyyy");
// OR
// services.AddExceptionless();
// OR
// services.AddExceptionless("API_KEY_HERE");

// adds a hosted service that will send sample events to Exceptionless.
services.AddHostedService<SampleService>();
})
.UseConsoleLifetime()
.ConfigureWebHostDefaults(builder => {
builder.Configure(app => {
app.UseRouting();
app.UseEndpoints(endpoints => {
endpoints.MapGet("/ping", context => {
var client = context.RequestServices.GetRequiredService<ExceptionlessClient>();
var logger = context.RequestServices.GetRequiredService<ILogger<Program>>();

// Submit a feature usage event directly using the client instance.
client.SubmitFeatureUsage("MapGet_Ping");

// This log message will get sent to Exceptionless since Exceptionless has be added to the logging system in Program.cs.
logger.LogWarning("Test warning message from ping");

try {
throw new Exception($"Handled Exception: {Guid.NewGuid()}");
}
catch (Exception handledException) {
// Use the ToExceptionless extension method to submit this handled exception to Exceptionless using the client instance from DI.
handledException.ToExceptionless(client).Submit();
}

try {
throw new Exception($"Handled Exception (Default Client): {Guid.NewGuid()}");
}
catch (Exception handledException) {
// Use the ToExceptionless extension method to submit this handled exception to Exceptionless using the default client instance (ExceptionlessClient.Default).
// This works and is convenient, but its generally not recommended to use static singleton instances because it makes testing and
// other things harder.
handledException.ToExceptionless().Submit();
}

// Unhandled exceptions will get reported since called UseExceptionless in the Startup.cs which registers a listener for unhandled exceptions.
throw new Exception($"Unhandled Exception: {Guid.NewGuid()}");
});
});
});
});
}
}
12 changes: 12 additions & 0 deletions samples/Exceptionless.SampleHosting/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"profiles": {
"Exceptionless.SampleAspNetCore": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:5000/ping",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
52 changes: 52 additions & 0 deletions samples/Exceptionless.SampleHosting/SampleService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace Exceptionless.SampleHosting {
internal class SampleService : IHostedService {
private readonly ExceptionlessClient _exceptionlessClient;
private readonly ILogger _logger;

public SampleService(ExceptionlessClient exceptionlessClient, ILogger<SampleService> logger) {
_exceptionlessClient = exceptionlessClient;
_logger = logger;
}

public Task StartAsync(CancellationToken cancellationToken) {
_logger.LogInformation("Starting sample service.");

// Submit a feature usage event directly using the client instance that is injected from the DI container.
_exceptionlessClient.SubmitFeatureUsage("SampleService");

// This log message will get sent to Exceptionless since Exceptionless has be added to the logging system in Program.cs.
_logger.LogWarning("Test warning message");

return Task.Run(() => {
try {
throw new Exception($"Handled Exception: {Guid.NewGuid()}");
}
catch (Exception handledException) {
// Use the ToExceptionless extension method to submit this handled exception to Exceptionless using the client instance from DI.
handledException.ToExceptionless(_exceptionlessClient).Submit();
}

try {
throw new Exception($"Handled Exception (Default Client): {Guid.NewGuid()}");
}
catch (Exception handledException) {
// Use the ToExceptionless extension method to submit this handled exception to Exceptionless using the default client instance (ExceptionlessClient.Default).
// This works and is convenient, but its generally not recommended to use static singleton instances because it makes testing and
// other things harder.
handledException.ToExceptionless().Submit();
}
}, cancellationToken);
}

public Task StopAsync(CancellationToken cancellationToken) {
_logger.LogInformation("Stopping sample service.");
return Task.CompletedTask;
}
}
}
24 changes: 24 additions & 0 deletions samples/Exceptionless.SampleHosting/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"Exceptionless": {
"ApiKey": "LhhP1C9gijpSKCslHHCvwdSIz298twx271n1l6xw",
"ServerUrl": "http://localhost:5000",
"DefaultData": {
"JSON_OBJECT": "{ \"Name\": \"Blake\" }",
"Boolean": true,
"Number": 1,
"Array": "1,2,3"
},
"DefaultTags": [ "xplat" ],
"Settings": {
"FeatureXYZEnabled": false
}
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<LangVersion>latest</LangVersion>
<AWSProjectType>Lambda</AWSProjectType>

<!-- This property makes the build directory similar to a publish directory and helps the AWS .NET Lambda Mock Test Tool find project dependencies. -->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Amazon.Lambda.Core" Version="1.2.0" />
<PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.1.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Exceptionless\Exceptionless.csproj" />
</ItemGroup>
</Project>
35 changes: 35 additions & 0 deletions samples/Exceptionless.SampleLambda/Function.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using Amazon.Lambda.Core;
using Exceptionless;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace Exceptionless.SampleLambda {
public class Function
{
public string FunctionHandler(string input, ILambdaContext context)
{
var client = new ExceptionlessClient(c => {
c.ApiKey = "LhhP1C9gijpSKCslHHCvwdSIz298twx271n1l6xw";
c.ServerUrl = "http://localhost:5000";

// read configuration values from environment variables
c.ReadFromEnvironmentalVariables();
});

// will automatically trigger a client.ProcessQueue call when this method completes even if there is an unhandled exception
using var _ = client.ProcessQueueDeferred();

client.SubmitFeatureUsage("Serverless Function");

try {
throw new Exception("Lambda error");
} catch (Exception ex) {
ex.ToExceptionless(client).Submit();
}

return input.ToLower();
}
}
}
49 changes: 49 additions & 0 deletions samples/Exceptionless.SampleLambda/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# AWS Lambda Empty Function Project

This starter project consists of:
* Function.cs - class file containing a class with a single function handler method
* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS

You may also have a test project depending on the options selected.

The generated function handler is a simple method accepting a string argument that returns the uppercase equivalent of the input string. Replace the body of this method, and parameters, to suit your needs.

## Here are some steps to follow from Visual Studio:

To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*.

To view your deployed function open its Function View window by double-clicking the function name shown beneath the AWS Lambda node in the AWS Explorer tree.

To perform testing against your deployed function use the Test Invoke tab in the opened Function View window.

To configure event sources for your deployed function, for example to have your function invoked when an object is created in an Amazon S3 bucket, use the Event Sources tab in the opened Function View window.

To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window.

To view execution logs of invocations of your function use the Logs tab in the opened Function View window.

## Here are some steps to follow to get started from the command line:

Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line.

Install Amazon.Lambda.Tools Global Tools if not already installed.
```
dotnet tool install -g Amazon.Lambda.Tools
```

If already installed check if new version is available.
```
dotnet tool update -g Amazon.Lambda.Tools
```

Execute unit tests
```
cd "BlueprintBaseName/test/BlueprintBaseName.Tests"
dotnet test
```

Deploy function to AWS Lambda
```
cd "BlueprintBaseName/src/BlueprintBaseName"
dotnet lambda deploy-function
```
16 changes: 16 additions & 0 deletions samples/Exceptionless.SampleLambda/aws-lambda-tools-defaults.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"Information": [
"This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
"To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
"dotnet lambda help",
"All the command line options for the Lambda command can be specified in this file."
],
"profile": "",
"region": "",
"configuration": "Release",
"framework": "netcoreapp3.1",
"function-runtime": "dotnetcore3.1",
"function-memory-size": 256,
"function-timeout": 30,
"function-handler": "Exceptionless.SampleLambda::Exceptionless.SampleLambda.Function::FunctionHandler"
}
Loading

0 comments on commit 70525fc

Please sign in to comment.