You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Power BI Service用户活动日志查询400错误排查求助

Power BI Admin ActivityEvents API 400错误:startDateTime/endDateTime需实现IConvertible

问题说明

我需要获取Power BI Service中的用户活动信息,包括指定时间范围内每个用户查看的报表、查看时间、查看时长、导出的可视化内容等。目前在调用/admin/activityevents接口获取报表查看记录时遇到400错误,已成功获取Access Token,但接口返回错误提示startDateTime和endDateTime参数需实现IConvertible。

错误详情

Access Token JSON: {'token_type': 'Bearer', 'expires_in': 3599, 'ext_expires_in': 3599, 'access_token': 'eyJ0eXAi.........'}
Fetching logs from 2024-06-11T00:00:00.000Z to 2024-06-11T23:59:59.999Z
Requesting logs with URL: https://api.powerbi.com/v1.0/myorg/admin/activityevents?startDateTime=2024-06-11T00%3A00%3A00.000Z&endDateTime=2024-06-11T23%3A59%3A59.999Z
Response Status Code: 400
HTTP error occurred: 400 Client Error: Bad Request for url: https://api.powerbi.com/v1.0/myorg/admin/activityevents?startDateTime=2024-06-11T00%3A00%3A00.000Z&endDateTime=2024-06-11T23%3A59%3A59.999Z
Response text: {"error":{"code":"BadRequest","message":"Bad Request","details":[{"message":"Object must implement IConvertible.","target":"startDateTime"},{"message":"Object must implement IConvertible.","target":"endDateTime"}]}}

问题原因

错误根源在于手动拼接URL并使用urlencode处理参数的方式,导致参数传递格式不符合Power BI API的解析要求。虽然时间字符串格式符合ISO 8601,但手动编码后的URL参数可能触发API内部的类型转换异常。

解决方案

使用requests库的params参数自动处理URL参数编码,而非手动拼接URL。这种方式能确保参数以API预期的格式传递,避免类型转换错误。

修改后的代码

import requests
import datetime
import pandas as pd
from urllib.parse import urlencode, unquote

# Constants (Replace these with your actual values)
CLIENT_ID = '-------------------'
TENANT_ID = '-------------------'
CLIENT_SECRET = '-----------------'

# Get access token using Microsoft identity platform (v2.0; MSAL)
def get_access_token():
    url = f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token"
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    body = {
        'grant_type': 'client_credentials',
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
        'scope': 'https://analysis.windows.net/powerbi/api/.default'
    }
    response = requests.post(url, headers=headers, data=body)
    response.raise_for_status()
    token_json = response.json()
    print("Access Token JSON:", token_json)  # Debugging output
    return token_json.get('access_token')

# Fetch activity logs
def fetch_activity_logs(access_token, start_datetime, end_datetime, continuation_token=None):
    headers = {
        'Authorization': f'Bearer {access_token}'
    }
    params = {
        'startDateTime': start_datetime,
        'endDateTime': end_datetime
    }
    if continuation_token:
        params['continuationToken'] = unquote(continuation_token)
    
    url = "https://api.powerbi.com/v1.0/myorg/admin/activityevents"
    
    # 保留调试输出,显示最终请求URL
    print(f"Requesting logs with URL: {url}?{urlencode(params)}")
    # 使用requests的params参数自动处理编码
    response = requests.get(url, headers=headers, params=params)
    print(f"Response Status Code: {response.status_code}")
    response.raise_for_status()
    return response.json()

# Main script
if __name__ == '__main__':
    try:
        access_token = get_access_token()
        # 设置单日(昨日)的时间范围,符合API要求格式
        yesterday = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=1)
        start_datetime = yesterday.strftime("%Y-%m-%dT00:00:00.000Z")
        end_datetime = yesterday.strftime("%Y-%m-%dT23:59:59.999Z")
        print(f"Fetching logs from {start_datetime} to {end_datetime}")  # Debugging output
        # 初始化存储所有日志的列表
        all_logs = []
        continuation_token = None
        # 循环处理分页
        while True:
            logs = fetch_activity_logs(access_token, start_datetime, end_datetime, continuation_token)
            all_logs.extend(logs.get('activityEventEntities', []))
            
            # 检查是否有续传令牌
            continuation_token = logs.get('continuationToken')
            if continuation_token:
                print(f"Continuation Token: {continuation_token}")  # Debugging output
            else:
                break  # 无续传令牌则退出循环
        # 打印原始日志以了解结构
        print("Raw logs:", all_logs)
        # 提取相关数据并创建DataFrame
        data = []
        for log in all_logs:
            if log.get('Activity') == 'ViewReport':  # 过滤查看报表的活动类型
                user = log.get('UserId')
                report = log.get('ItemName')
                start_time = log.get('CreationTime')
                data.append({'User': user, 'Report': report, 'StartTime': start_time})
        # 创建DataFrame
        df = pd.DataFrame(data)
        print(df)
        # 可选:保存到CSV文件
        df.to_csv('powerbi_viewreport_logs_today_filtered.csv', index=False)
    except requests.exceptions.HTTPError as err:
        print(f"HTTP error occurred: {err}")
        print(f"Response text: {err.response.text}")
    except Exception as err:
        print(f"An error occurred: {err}")

额外注意事项

  • 确保服务主体拥有Power BI租户管理员或工作区管理员权限,否则即使参数正确也会返回权限错误。
  • 时间范围不能超过API允许的最大跨度(目前Power BI API允许的最大时间范围为30天)。

内容的提问来源于stack exchange,提问作者Aaron Ramsey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 11:52:02