I am trying to create a function app on Azure with an Event Hub trigger using a managed identity. I seem to have created everything so that all the references resolve, but when I send a message to the event hub, the function app is not getting triggered (or at least, I’m not seeing the log entry it should be producing).
Trying to follow the documentation here.
Provisioning using Terraform:
main.tf
variable "resource_group_name" {}
variable "location" { default = null }
variable "function_app_name" {}
variable "event_hub_name" {}
resource "azurerm_resource_group" "rg" {
name = var.resource_group_name
location = var.location
}
resource "azurerm_service_plan" "sp" {
name = "fnappserviceplan"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
os_type = "Linux"
sku_name = "B1"
}
resource "azurerm_eventhub_namespace" "hub" {
name = var.event_hub_name
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
sku = "Standard"
capacity = 1
}
resource "azurerm_eventhub" "hub" {
name = "myEventHub"
namespace_name = azurerm_eventhub_namespace.hub.name
resource_group_name = azurerm_resource_group.rg.name
partition_count = 2
message_retention = 1
}
resource "azurerm_storage_account" "fnapp" {
name = "safnapp"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_linux_function_app" "fnapp" {
name = var.function_app_name
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
service_plan_id = azurerm_service_plan.sp.id
storage_account_name = azurerm_storage_account.fnapp.name
storage_account_access_key = azurerm_storage_account.fnapp.primary_access_key
app_settings = {
# tried this but it doesn't recognize the connection, so I went with the connection string instead
# "EVENTHUB__fullyQualifiedNamespace" = "${azurerm_eventhub_namespace.hub.name}.servicebus.windows.net"
"EVENTHUB" = azurerm_eventhub_namespace.hub.default_primary_connection_string
"EVENTHUB_CONSUMER_GROUP" = azurerm_eventhub_consumer_group.fnapp.name
}
site_config {
always_on = true
application_stack {
python_version = "3.11"
}
}
identity {
type = "SystemAssigned"
}
}
resource "azurerm_eventhub_consumer_group" "fnapp" {
name = "${var.function_app_name}ConsumerGroup"
namespace_name = azurerm_eventhub_namespace.hub.name
eventhub_name = azurerm_eventhub.hub.name
resource_group_name = azurerm_resource_group.rg.name
}
And then the main function:
function_app.py
import logging
import os
import azure.functions as func
app = func.FunctionApp()
@app.function_name(name="mylistener")
@app.event_hub_message_trigger(arg_name="hub",
event_hub_name="myEventHub",
connection="EVENTHUB",
consumer_group=os.getenv("EVENTHUB_CONSUMER_GROUP", "$Default"))
def myeventlistener(hub: func.EventHubEvent):
event_body = hub.get_body().decode('utf-8')
logging.info(f'Python EventHub trigger processed an event: {event_body}')
After provisioning, I add the "Azure Event Hubs Data Receiver" role to this function app on the resource group. (And "Azure Event Hubs Data Owner" to myself for my own interactions with the event hub.)
I then deploy the code using func azure functionapp publish MyFunctionAppName
, and monitor using func azure functionapp logstream MyFunctionAppName
. (This logstream is where I expect to see the logging.info()
output. Or at least some system logs indicating the function has been triggered. Is this correct?)
When inspecting the connection on the Azure portal (mylistener function > Integration > Triggers > Azure Event Hub) all the parameters appear correct and the Connection seems to be recognized – it’s not giving me "No connection found" or anything, it’s using the named connection I set in the app settings.
After waiting for all the setup/launching/initializing to settle down, I then publish a (plaintext) message to the event hub (not the namespace). I have tried sending specifically to each partition. I expect the log message to appear but it does not. I see no indication that the function is getting triggered.
UPDATE
ChatGPT suggested that this doesn’t use managed identities if I feed it a connection string, and instead I should set EVENTHUB = azurerm_eventhub.hub.name
in order to use managed identities. It was double-minded on whether the argument in Python should be connection="EVENTHUB"
or connection="EVENTHUB__fullyQualifiedNamespace"
. I tried both (while uncommenting the one line in the tf app_settings), and with both, it gives me "No existing connections available" when I check the trigger’s connection on the portal. I also get the message "Azure.Messaging.EventHubs: The connection string could not be parsed; either it was malformed or contains no well-known tokens."
2
Answers
Credit to @Pravallika KV's answer for containing the information I needed. TL/DR version follows.
The update to the OP was the correct configuration. I was looking in the wrong place for logs so it did not appear to be working. Also, with this configuration, the "Integration" tab on the Function shows "No existing connections available" under the Event Hub trigger, implying there is no connection, even though it is in fact connecting and triggering properly. (Bug?)
The following modification to the OP Terraform setup works:
main.tf
function_app.py
in OP may be used as is.connection
should be the portion of the environment variable before the__fullyQualifiedNamespace
. So, for example, with an environment variable calledEVENTHUB__fullyQualifiedNamespace
, you wantconnection="EVENTHUB"
. Be sure not to also include an environment variable calledEVENTHUB
.I have not found a way to view the logs from the log stream, even by forcing to stdout. However, the logs are accessible using the (small charge paid service) Application Insights, which must be enabled in order to view them. This can be done using the web portal or through Terraform. Once enabled, invocations are recorded under the "Invocations" tab of the Function. Log entries will appear individually when selecting a specific run.
Follow below steps to establish connection between Azure function app and Event Hub using managed identity.
Event Hub=>Access Role(IAM)=>Add Role Assignment
, assign Azure EventHub Data Owner and Azure Event Hub Data Receiver to Function App’s Managed Identity.<CONNECTION_NAME_PREFIX>__fullyQualifiedNamespace=<eventhub_name>.servicebus.windows.net
underFunctionapp=>settings=>Environment Variables=>App Settings
:CONNECTION_NAME_PREFIX should be the connection value you have used in the function code.
Code Snippet:
You can check the function logs under
Function=>Invocation Logs
. select the particular log to see the detailed output/invocation.