Azure Functions not Sending Email or Printing Console Log - azure

I have create a Function App at Azure Painel. Then my function project looks like this
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsDashboard": "DefaultEndpointsProtocol=...",
"AzureWebJobsStorage": "DefaultEndpointsProtocol=...",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}
host.json
{
"version": "2.0",
"functionTimeout": "00:10:00",
"logging": {
"fileLoggingMode": "debugOnly",
"logLevel": {
"Function": "Trace",
"default": "Trace"
},
"console": {
"isEnabled": "true"
}
}
}
MyFunction.cs
[FunctionName("MyFunction")]
public static async Task Run([TimerTrigger("0 0 * * * *", RunOnStartup = true)]TimerInfo ti, ILogger log)
{
log.LogInformation($"Timer trigger function started at: {DateTime.Now}");
var lib = new MyLibJobs();
await lib.Run();
log.LogInformation($"Timer trigger function executed at: {DateTime.Now}");
}
public async Task Run()
{
var logger = new LoggerConfiguration().WriteTo.Console().CreateLogger();
logger.Information("=== === === === === === === === === === === === === === ===");
logger.Information("shometing");
ElasticEmail.Send(...);
...
}
When I run the function, I'm able to get the first log. But after that nothing more seems to work (running locally all works). Inside MyLibJobs I have LoggerConfiguration and ElasticEmail but none of this seems to be called. No console logs or no emails been sent.
What could I be missing here?

change the code to receive ILogger in the constructor, it will print the errors. About the messages I do believe it's throwing and exception, which you also be able to catch using the provided code:
using System;
using Microsoft.Extensions.Logging;
public class MyLibJobs
{
private ILogger _log;
public MyLibJobs(ILogger log)
{
_log = _log;
}
public async Task Run()
{
_log.Information("=== === === === === === === === === === === === === === ===");
_log.Information("shometing");
try
{
ElasticEmail.Send(...);
}
catch(Exception ex)
{
_log.LogError(ex, "error when trying to send email);
throw;
}
}
}
[FunctionName("MyFunction")]
public static async Task Run([TimerTrigger("0 */1 * * * *", RunOnStartup = true)]TimerInfo ti, ILogger log)
{
log.LogInformation($"Timer trigger function started at: {DateTime.Now}");
var lib = new MyLibJobs(log);
await lib.Run();
log.LogInformation($"Timer trigger function executed at: {DateTime.Now}");
}

Update:
If you want to use EMAIL on Azure Web App, the only way is via an SMTP relay. The third party service such as SendGrid provides these type of services.
Original Answer:
Is this what you want?
This is mycode:
Function1.cs:
using System;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
using Serilog;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace ConsoleLogFunction
{
public static class Function1
{
public class MyLibJobs
{
public async Task Run()
{
var logger = new LoggerConfiguration().WriteTo.Console().CreateLogger();
logger.Information("=== === === === === === === === === === === === === === ===");
logger.Information("shometing");
}
}
[FunctionName("Function1")]
public static async Task Run([TimerTrigger("*/1 * * * * *")]TimerInfo myTimer, ILogger log)
{
log.LogInformation($"Timer trigger function started at: {DateTime.Now}");
var lib = new MyLibJobs();
await lib.Run();
log.LogInformation($"Timer trigger function executed at: {DateTime.Now}");
}
}
}
host.json:
{
"version": "2.0",
"functionTimeout": "00:10:00",
"logging": {
"fileLoggingMode": "debugOnly",
"logLevel": {
"Function": "Information",
"default": "Trace"
},
"console": {
"isEnabled": "true"
}
}
}
please note that you close the information level.

Okay... It seems that the main problem it wasn't with the log or email, well maybe with the log (a little), but not with the email.
Because I had the same code running on Azure WebJob (and working), I thought that it should be working in the same way with Azure Functions (which seems not). That's why my question was focused on logs and email, but the issue could be related to something else.
Indeed serilog seems to not work on Azure Functions. So it makes the Thiago Custodio answer right. I should be using Microsoft.Extensions.Logging.ILogger.
During the program steps, to trigger the email, something else should be done, where I'll explain
The program basically do the follow steps:
a. log that it started
b. download some csv data
c. write these csv data into a csv file
d. read the csv file, compare with another one and write another csv file
e. send the csv file diff to another api
f. finally send email with the summary about what was done
Doing some researches, I read that Path.GetTempPath() changes accordingly the function runs. That said I think that this could be the main the problem. I just don't know what exactly because I have never got an error, the Functions just ran like no tomorrow.
To workaround this, I decide to write my files inside "D:\home\data\temp". There I can see my files and all steps are running correctly.
I can't say that this is the write answer. But it's the one that worked for me.

Related

Azure Durable Functions - OrchestrationTrigger stuck

I am new to azure durable functions. I have created a sample azure durable function using vs 2019. I am running default generated azure durable function template code locally with azure storage enumerator and when I run the durable function, the OrchestrationTrigger stuck and not able to resume.
The hub name is samplehubname. There a pending records present in the samplehubnameInstances azure table but there is no records in the samplehubnameHistory azure table.
There is no exception and no errors in the code.
SampleFunction.cs
public static class SampleFunction
{
[FunctionName("SampleFunction")]
public static async Task<List<string>> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
var outputs = new List<string>();
// Replace "hello" with the name of your Durable Activity Function.
outputs.Add(await context.CallActivityAsync<string>("SampleFunction_Hello", "Tokyo"));
// returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"]
return outputs;
}
[FunctionName("SampleFunction_Hello")]
public static string SayHello([ActivityTrigger] string name, ILogger log)
{
log.LogInformation($"Saying hello to {name}.");
return $"Hello {name}!";
}
[FunctionName("SampleFunction_HttpStart")]
public static async Task<HttpResponseMessage> HttpStart(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req,
[DurableClient] IDurableOrchestrationClient starter,
ILogger log)
{
// Function input comes from the request content.
string instanceId = await starter.StartNewAsync("SampleFunction", null);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
return starter.CreateCheckStatusResponse(req, instanceId);
}
}
local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"AzureWebJobsSecretStorageType": "files", //files
"MyTaskHub": "samplehubname"
}
}
host.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensions": {
"durableTask": {
"hubName": "%MyTaskHub%"
}
}
}
samplehubname-control-03 Message Queue
{"$type":"DurableTask.AzureStorage.MessageData","ActivityId":"72b75a34-e403-4772-aed0-fbb10039795a","TaskMessage":{"$type":"DurableTask.Core.TaskMessage","Event":{"$type":"DurableTask.Core.History.ExecutionStartedEvent","OrchestrationInstance":{"$type":"DurableTask.Core.OrchestrationInstance","InstanceId":"f8d0499a4297480c8bdf4a56954861d3","ExecutionId":"2e46b87e4cf74c2dab572d92e012bded"},"EventType":0,"ParentInstance":null,"Name":"Function1","Version":"","Input":"null","Tags":null,"EventId":-1,"IsPlayed":false,"Timestamp":"2021-09-21T15:41:35.0156514Z"},"SequenceNumber":0,"OrchestrationInstance":{"$type":"DurableTask.Core.OrchestrationInstance","InstanceId":"f8d0499a4297480c8bdf4a56954861d3","ExecutionId":"2e46b87e4cf74c2dab572d92e012bded"}},"CompressedBlobName":null,"SequenceNumber":1,"Sender":{"$type":"DurableTask.Core.OrchestrationInstance","InstanceId":"","ExecutionId":""}}
Any help will appreciated.
If your orchestration code has contain a loop too much, the guidance in our Eternal orchestration documentation.
In your code there is not much loop available. So, you need to use the durable functions eternal orchestrations TerminateAsync (.NET) method of the orchestration client binding to stop it.
Add your durable function into application insights to check the clear view of issue. It may help to fix the issue.
Check the similar issue here.
Try the steps and use fan in/ fan out in durable function durable functions patterns fan out and fan in

Azure Functions V3 ILogger using DI - messages from logger not in traces

In my Azure Function I am trying to log using the DI container; however I am unable to get the logger to display messages in the Log Stream or the Traces in Application Insights. I have created a minimal code sample project which I am testing using the Azure Portal (Code + Test) shown here.
I've tried using Serilog same result.
I've tried removing the log parameter from Function1 - then I get no errors nor messages
I assume I'm missing something simple/obvious but I'm stuck.
namespace LoggingApiTest {
public class Function1 {
private readonly ILogger<Function1> logger;
public Function1(ILogger<Function1> logger)
{
this.logger = logger;
logger.LogInformation("In Function1 ctor using DI created Logger");
}
[FunctionName("Function1")]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "Test")] HttpRequest req,
ILogger log) {
logger.LogInformation("Hello from DI Logger");
log.LogInformation("Hello from logger passed as parameter");
return new OkObjectResult("Hello");
}
}
}
startup
namespace LoggingApiTest {
public class Startup : FunctionsStartup {
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddLogging();
}
}
}
host.json
enter code here{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
},
"logLevel": {
"default": "Information"
}
}
}
}
The LogStream shows 2021-07-16T12:59:50.705 [Information] Executing 'Function1' (Reason='This function was programmatically called via the host APIs.', Id=b8238346-7ff7-450d-a7f0-abc8f1a210fa) 2021-07-16T12:59:50.705 [Information] Hello from logger passed as parameter 2021-07-16T12:59:50.705 [Information] Executed 'Function1' (Succeeded, Id=b8238346-7ff7-450d-a7f0-abc8f1a210fa, Duration=1ms)
In your logging section of your host.json file, try adding your solution namespace with the logLevel. This should enable logging at a logLevel of Information and above.
{
"version": "2.0",
"logging": {
"logLevel": {
"LoggingApiTest": "Information"
}
}
}
https://github.com/Azure/azure-functions-host/issues/4425#issuecomment-492678381

How can I inject the default azure function logger in other classes?

I´m using azure functions using dotnet core 3.1 and I cannot make my custom logs work as expected.
In my values section of the local.settings.json file i put the following key: APPINSIGHTS_INSTRUMENTATIONKEY and i read on the docs that the functions runtime add the log automatically.
I can see the default logs on the application insights panel, but my custom logs are not being write there. On my class I did this:
private readonly ILogger<LoginService> _logger;
public CustomService(ILogger<CustomService> logger)
{
_logger = logger;
}
public void Test()
{
_logger.LogError("TestLog");
}
How is the proper way of injecting the default logging in the constructor of other classes which is not the function method itself?
ILogger is indeed not a valid injections. ILogger does work and
creates a filter of type T. However you need to manually add the
ability to listen to custom filters (in this case your class) for them
to show up. you can do that in host.json. Here's a sample.
host.json:
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
},
"logLevel": {
"Hollan.Functions.HttpTrigger": "Information"
}
}
}
HttpTrigger.cs
public class HttpTrigger
{
private readonly ILogger<HttpTrigger> _log;
public HttpTrigger(ILogger<HttpTrigger> log)
{
_log = log;
}
[FunctionName("HttpTrigger")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req)
{
_log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
string responseMessage = string.IsNullOrEmpty(name)
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
: $"Hello, {name}. This HTTP triggered function executed successfully.";
return new OkObjectResult(responseMessage);
}
}
}
Source: https://github.com/Azure/Azure-Functions/issues/1484

Azure EventHub and Durable Functions

Literally trying out to make do of something I am not good at.
I have read upon the durable function overview here - https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview.
There is a topic on using Bindings to use it on an Event Hub Trigger, but there is not really a working example, I followed what was there and came up with this binding in my function.json,
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "myEventHubMessage",
"direction": "in",
"path": "testinhub",
"connection": "Endpoint=sb://dev-testingeventhubinns.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=lLassdff5Y/esH8/CaXDOWH0jF2JtZBQhQeFoCtfqYs=",
"consumerGroup": "$Default"
},
{
"type": "eventHub",
"name": "outputEventHubMessage",
"connection": "Endpoint=sb://dev-testingeventhuboutns.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=4yuasdff7Lzu+mQJFVlnlozUItqFY1L3WW/kJnpTjq8=",
"path": "testouthub",
"direction": "out"
}
],
"disabled": false,
"entryPoint": "EventTriggerFunction.EventHubTriggerClass.Run"
}
My code in entirety is as follows,
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.EventHubs;
using System;
namespace EventTriggerFunction
{
public static class EventHubTriggerClass
{
[FunctionName("EventHubTrigger")]
public static async Task<List<string>> Run([OrchestrationTrigger] DurableOrchestrationContext context)
{
await context.CallActivityAsync<string>("EventHubTrigger_Send", "Hello World");
return null;
}
[FunctionName("EventHubTrigger_Send")]
public static void SendMessages([EventHubTrigger("testinhub", Connection = "ConnectionValue")] EventData[] eventHubMessages, ILogger log)
{
var exceptions = new List<Exception>();
foreach (EventData message in eventHubMessages)
{
try
{
log.LogInformation($"C# Event Hub trigger function processed a message: {Encoding.UTF8.GetString(message.Body)}");
}
catch (Exception e)
{
// We need to keep processing the rest of the batch - capture this exception and continue.
// Also, consider capturing details of the message that failed processing so it can be processed again later.
exceptions.Add(e);
}
}
}
}
}
If I send a message using the function, I can not see it on my testouthub event hub. Not really sure how this Durable function and EventHub Trigger works hand in hand.
I think you are mixing it up a bit. When using the attributes like FunctionName and EventHubTrigger you do not need to supply the function.json. It's either function.json or with attributes.
If you are trying to receive messages from 1 eventhub and passing it on to the next, then something like this below will also do the trick.
There's no need to use DurableFunctions for this and the Azure Function runtime will scale by itself if there are many messages, see this
[FunctionName("EventHubTriggerCSharp")]
[return: EventHub("outputEventHubMessage", Connection = "EventHubConnectionAppSetting")]
public static void Run([EventHubTrigger("samples-workitems", Connection = "EventHubConnectionAppSetting")] string myEventHubMessage, ILogger log)
{
log.LogInformation($"C# Event Hub trigger function processed a message: {myEventHubMessage}");
return myEventHubMessage;
}
An additional tip: I would not paste your full connectionstring into StackOverflow. Maybe it's wise to immediately create new AccessKeys for your eventhubs.

Azure Functions - TimerTrigger - Error when ran locally

I have an issue when I start Azure Functions project locally. I am using AzureFunctions v1 (.Net Framework). The error I get is following:
This is my local.settings.json:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"AzureWebJobsDashboard": "UseDevelopmentStorage=true",
"StorageConnectionString": "UseDevelopmentStorage=true"
}
}
I googled the error without much luck.
What could be the couse of this error? Is it about configuration? Also, these are all TimerTrigger functions.
Thanks..
EDIT:
public class TimerPing: _BaseTrigger
{
static TimerPing()
{
Init();
}
[FunctionName("Timer_Ping")]
public static void Run([TimerTrigger("0 * * * * *", RunOnStartup = true)]TimerInfo myTimer, TraceWriter log)
{
//TryRun(() =>
//{
// ErrorHandler.InsertServiceLog(
// $"{SERVICE_NAME} - Ping",
// "ping",
// SensorType.Success);
//});
}
}
Please note that everything is commented out and this error still presists.
Also, in Output window on VS 2017 I get this:
Exception thrown: 'System.NotSupportedException' in mscorlib.dll
And I am running this locally using Azure.Functions.Cli\1.0.12
From the error screenshot you provided, The type initializer xxx in TimerPing.TimerPing(static constructor) throw an exception, so you should check the Init() method in it. Hope it helps.

Resources