Exemplo n.º 1
0
def get_classroom(url_rid, url_semester):
    """教室查询"""
    # decrypt identifier in URL
    try:
        _, room_id = decrypt(url_rid, resource_type='room')
    except ValueError:
        return render_template("common/error.html",
                               message=MSG_INVALID_IDENTIFIER)

    # RPC to get classroom timetable
    with elasticapm.capture_span('rpc_get_classroom_timetable'):
        try:
            room = APIServer.get_classroom_timetable(url_semester, room_id)
        except Exception as e:
            return handle_exception_with_error_page(e)

    with elasticapm.capture_span('process_rpc_result'):
        cards = defaultdict(list)
        for card in room.cards:
            day, time = lesson_string_to_tuple(card.lesson)
            cards[(day, time)].append(card)

    empty_5, empty_6, empty_sat, empty_sun = _empty_column_check(cards)

    available_semesters = semester_calculate(url_semester, room.semesters)

    return render_template('query/room.html',
                           room=room,
                           cards=cards,
                           empty_sat=empty_sat,
                           empty_sun=empty_sun,
                           empty_6=empty_6,
                           empty_5=empty_5,
                           available_semesters=available_semesters,
                           current_semester=url_semester)
Exemplo n.º 2
0
def test_transaction_sample_rate_dynamic(elasticapm_client, not_so_random):
    elasticapm_client.config.update(version="1", transaction_sample_rate=0.4)
    for i in range(10):
        elasticapm_client.begin_transaction("test_type")
        with elasticapm.capture_span("xyz"):
            pass
        elasticapm_client.end_transaction("test")

    transactions = elasticapm_client.events[TRANSACTION]
    spans_per_transaction = defaultdict(list)
    for span in elasticapm_client.events[SPAN]:
        spans_per_transaction[span["transaction_id"]].append(span)

    # seed is fixed by not_so_random fixture
    assert len([t for t in transactions if t["sampled"]]) == 3
    for transaction in transactions:
        assert transaction[
            "sampled"] or not transaction["id"] in spans_per_transaction
        assert transaction["sampled"] or not "context" in transaction

    elasticapm_client.config.update(version="1", transaction_sample_rate=1.0)
    for i in range(5):
        elasticapm_client.begin_transaction("test_type")
        with elasticapm.capture_span("xyz"):
            pass
        elasticapm_client.end_transaction("test")

    transactions = elasticapm_client.events[TRANSACTION]

    # seed is fixed by not_so_random fixture
    assert len([t for t in transactions if t["sampled"]]) == 8
Exemplo n.º 3
0
def test_transaction_span_frames_min_duration_dynamic(elasticapm_client):
    elasticapm_client.config.update(version="1", span_frames_min_duration=20)
    elasticapm_client.begin_transaction("test_type")
    with elasticapm.capture_span("noframes", duration=0.001):
        pass
    with elasticapm.capture_span("frames", duration=0.04):
        pass
    elasticapm_client.end_transaction("test")

    spans = elasticapm_client.events[SPAN]

    assert len(spans) == 2
    assert spans[0]["name"] == "noframes"
    assert "stacktrace" not in spans[0]

    assert spans[1]["name"] == "frames"
    assert spans[1]["stacktrace"] is not None

    elasticapm_client.config.update(version="1", span_frames_min_duration=-1)
    elasticapm_client.begin_transaction("test_type")
    with elasticapm.capture_span("frames"):
        pass
    with elasticapm.capture_span("frames", duration=0.04):
        pass
    elasticapm_client.end_transaction("test")

    spans = elasticapm_client.events[SPAN]

    assert len(spans) == 4
    assert spans[2]["name"] == "frames"
    assert spans[2]["stacktrace"] is not None

    assert spans[3]["name"] == "frames"
    assert spans[3]["stacktrace"] is not None
def test_transaction_fast_exit_span(elasticapm_client):
    elasticapm_client.begin_transaction("test_type")
    with elasticapm.capture_span(span_type="x",
                                 name="x",
                                 leaf=True,
                                 duration=2):  # not dropped, too long
        pass
    with elasticapm.capture_span(span_type="y",
                                 name="y",
                                 leaf=True,
                                 duration=0.1):  # dropped
        pass
    with elasticapm.capture_span(span_type="z",
                                 name="z",
                                 leaf=False,
                                 duration=0.1):  # not dropped, not exit
        pass
    elasticapm_client.end_transaction("foo", duration=2.2)
    transaction = elasticapm_client.events[constants.TRANSACTION][0]
    spans = elasticapm_client.events[constants.SPAN]
    breakdown = elasticapm_client._metrics.get_metricset(
        "elasticapm.metrics.sets.breakdown.BreakdownMetricSet")
    metrics = list(breakdown.collect())
    assert len(spans) == 2
    assert transaction["span_count"]["started"] == 3
    assert transaction["span_count"]["dropped"] == 1
    assert metrics[0]["span"]["type"] == "x"
    assert metrics[0]["samples"]["span.self_time.sum.us"]["value"] == 2000000
    assert metrics[1]["span"]["type"] == "y"
    assert metrics[1]["samples"]["span.self_time.sum.us"]["value"] == 100000
Exemplo n.º 5
0
def test_compressed_spans_not_counted(elasticapm_client):
    elasticapm_client.begin_transaction("test")
    with elasticapm.capture_span(
            "test1",
            span_type="a",
            span_subtype="b",
            span_action="c",
            leaf=True,
            duration=2,
            extra={"destination": {
                "service": {
                    "resource": "x"
                }
            }},
    ) as span1:
        pass
    with elasticapm.capture_span(
            "test2",
            span_type="a",
            span_subtype="b",
            span_action="c",
            leaf=True,
            duration=3,
            extra={"destination": {
                "service": {
                    "resource": "x"
                }
            }},
    ) as span2:
        pass
    elasticapm_client.end_transaction("test")
    transaction = elasticapm_client.events[TRANSACTION][0]
    spans = elasticapm_client.events[SPAN]
    assert len(spans) == transaction["span_count"]["started"] == 1
    assert transaction["span_count"]["dropped"] == 0
Exemplo n.º 6
0
def bench_transaction_spans(client):
    client.begin_transaction("test")
    with capture_span("test1"):
        with capture_span("test2"):
            with capture_span("test3"):
                pass
    client.end_transaction("test", "OK")
def test_span_compression_disabled(elasticapm_client):
    transaction = elasticapm_client.begin_transaction("test")
    with elasticapm.capture_span(
            "test",
            span_type="a",
            span_subtype="b",
            span_action="c",
            leaf=True,
            duration=2,
            extra={"destination": {
                "service": {
                    "resource": "x"
                }
            }},
    ) as span1:
        assert not span1.is_compression_eligible()
    with elasticapm.capture_span(
            "test",
            span_type="a",
            span_subtype="b",
            span_action="c",
            leaf=True,
            duration=3,
            extra={"destination": {
                "service": {
                    "resource": "x"
                }
            }},
    ) as span2:
        assert not span2.is_compression_eligible()
    elasticapm_client.end_transaction("test")
    spans = elasticapm_client.events[SPAN]
    assert len(spans) == 2
    span = spans[0]
    assert "composite" not in span
Exemplo n.º 8
0
def test_nested_spans(elasticapm_client):
    elasticapm_client.begin_transaction("request", start=0)
    with elasticapm.capture_span("test", span_type="template", span_subtype="django", start=5, duration=15):
        with elasticapm.capture_span("test", span_type="db", span_subtype="mysql", start=10, duration=5):
            pass
        with elasticapm.capture_span("test", span_type="db", span_subtype="mysql", start=15, duration=5):
            pass
    elasticapm_client.end_transaction("test", "OK", duration=25)
    breakdown = elasticapm_client._metrics.get_metricset("elasticapm.metrics.sets.breakdown.BreakdownMetricSet")
    data = list(breakdown.collect())
    assert len(data) == 3
    asserts = 0
    for elem in data:
        if "span.self_time.sum.us" in elem["samples"]:
            if elem["span"] == {"type": "app", "subtype": ""}:
                assert elem["transaction"] == {"name": "test", "type": "request"}
                assert elem["samples"]["span.self_time.sum.us"]["value"] == 10000000
                assert elem["samples"]["span.self_time.count"]["value"] == 1
                asserts += 1
            elif elem["span"] == {"type": "db", "subtype": "mysql"}:
                assert elem["samples"]["span.self_time.count"]["value"] == 2
                assert elem["samples"]["span.self_time.sum.us"]["value"] == 10000000
                assert elem["transaction"] == {"name": "test", "type": "request"}
                asserts += 1
            elif elem["span"] == {"type": "template", "subtype": "django"}:
                assert elem["samples"]["span.self_time.count"]["value"] == 1
                assert elem["samples"]["span.self_time.sum.us"]["value"] == 5000000
                assert elem["transaction"] == {"name": "test", "type": "request"}
                asserts += 1
    assert asserts == 3
Exemplo n.º 9
0
def test_nested_spans(elasticapm_client):
    transaction = elasticapm_client.begin_transaction("request")
    time.sleep(0.005)
    with elasticapm.capture_span("test",
                                 span_type="template",
                                 span_subtype="django"):
        time.sleep(0.005)
        with elasticapm.capture_span("test",
                                     span_type="db",
                                     span_subtype="mysql"):
            time.sleep(0.005)
        with elasticapm.capture_span("test",
                                     span_type="db",
                                     span_subtype="mysql"):
            time.sleep(0.005)
    time.sleep(0.005)
    elasticapm_client.end_transaction("test", "OK")
    breakdown = elasticapm_client._metrics.get_metricset(
        "elasticapm.metrics.sets.breakdown.BreakdownMetricSet")
    data = list(breakdown.collect())
    assert len(data) == 4
    asserts = 0
    for elem in data:
        if "transaction.breakdown.count" in elem["samples"]:
            assert elem["samples"]["transaction.breakdown.count"]["value"] == 1
            assert elem["transaction"] == {"name": "test", "type": "request"}
            asserts += 1
        elif "span.self_time.sum.us" in elem["samples"]:
            if elem["span"] == {"type": "app", "subtype": ""}:
                assert elem["transaction"] == {
                    "name": "test",
                    "type": "request"
                }
                assert 10000 < elem["samples"]["span.self_time.sum.us"]["value"]
                assert elem["samples"]["span.self_time.count"]["value"] == 1
                asserts += 1
            elif elem["span"] == {"type": "db", "subtype": "mysql"}:
                assert elem["samples"]["span.self_time.count"]["value"] == 2
                assert 10000 < elem["samples"]["span.self_time.sum.us"]["value"]
                assert elem["transaction"] == {
                    "name": "test",
                    "type": "request"
                }
                asserts += 1
            elif elem["span"] == {"type": "template", "subtype": "django"}:
                assert elem["samples"]["span.self_time.count"]["value"] == 1
                assert 5000 < elem["samples"]["span.self_time.sum.us"]["value"]
                assert elem["transaction"] == {
                    "name": "test",
                    "type": "request"
                }
                asserts += 1
    assert asserts == 4

    transaction_metrics = elasticapm_client._metrics.get_metricset(
        "elasticapm.metrics.sets.transactions.TransactionsMetricSet")
    transaction_data = list(transaction_metrics.collect())
    assert len(transaction_data) == 1
    assert 25000 < transaction_data[0]["samples"][
        "transaction.duration.sum.us"]["value"]
Exemplo n.º 10
0
def ics_download(calendar_token):
    """
    iCalendar ics file download

    因为课表会更新,所以 ics 文件只能在这里动态生成,不能在日历订阅页面就生成
    """
    from flask import send_from_directory, current_app
    from everyclass.server.db.dao import CalendarTokenDAO
    from everyclass.server.db.model import Semester
    from everyclass.server.calendar import ics_generator
    from everyclass.server.utils.rpc import HttpRpc
    from everyclass.server.utils import teacher_list_fix
    from everyclass.server.utils import teacher_list_to_str
    from everyclass.server.utils import lesson_string_to_dict

    result = CalendarTokenDAO.find_calendar_token(token=calendar_token)
    if not result:
        return 'invalid calendar token', 404

    with elasticapm.capture_span('rpc_find_people'):
        rpc_result = HttpRpc.call_with_error_page('{}/v1/{}/{}/{}'.format(
            current_app.config['API_SERVER_BASE_URL'], result['type'],
            result['sid'] if result['type'] == 'student' else result['tid'],
            result['semester']),
                                                  params={
                                                      'week_string': 'true'
                                                  },
                                                  retry=True)
        if isinstance(rpc_result, str):
            return rpc_result
        api_response = rpc_result

    with elasticapm.capture_span('process_rpc_result'):
        semester = Semester(result['semester'])

        courses = dict()
        for each_class in api_response['course']:
            day, time = lesson_string_to_dict(each_class['lesson'])
            if (day, time) not in courses:
                courses[(day, time)] = list()
            courses[(day, time)].append(
                dict(name=each_class['name'],
                     teacher=teacher_list_to_str(
                         teacher_list_fix(each_class['teacher'])),
                     week=each_class['week'],
                     week_string=each_class['week_string'],
                     classroom=each_class['room'],
                     classroom_id=each_class['rid'],
                     cid=each_class['cid']))

    ics_generator.generate(name=api_response['name'],
                           courses=courses,
                           semester=semester,
                           ics_token=calendar_token)

    return send_from_directory("../../calendar_files",
                               calendar_token + ".ics",
                               as_attachment=True,
                               mimetype='text/calendar')
Exemplo n.º 11
0
    def ListRecommendations(self, request, context):
        # manually populate service map
        # this can be removed once 7.8 is out and the python agent adds this by itself
        product_catalog_destination_info = {
            "address": os.environ.get('PRODUCT_CATALOG_SERVICE_ADDR', ''),
            "port": int(os.environ.get('PORT', 8080)),
            "service": {
                "name": "grpc",
                "resource": os.environ.get('PRODUCT_CATALOG_SERVICE_ADDR', ''),
                "type": "external"
            },
        }

        trace_parent = self.extract_trace_parent(context)
        transaction = client.begin_transaction('request',
                                               trace_parent=trace_parent)
        request_dict = MessageToDict(request)
        elasticapm.label(**{'request': request_dict})
        max_responses = 5
        # fetch list of products from product catalog stub
        list_product_req = demo_pb2.Empty()
        with elasticapm.capture_span(
                '/hipstershop.ProductCatalogService/ListProducts',
                labels=MessageToDict(list_product_req),
                extra={"destination":
                       product_catalog_destination_info}) as span:
            trace_parent = transaction.trace_parent.copy_from(
                span_id=span.id, trace_options=TracingOptions(recorded=True))
            cat_response, call = product_catalog_stub.ListProducts.with_call(
                list_product_req,
                metadata=[(constants.TRACEPARENT_HEADER_NAME,
                           trace_parent.to_string())])
        with elasticapm.capture_span('CalculateRecommendations',
                                     span_subtype='grpc',
                                     span_action='calculate') as span:
            product_ids = [x.id for x in cat_response.products]
            filtered_products = list(
                set(product_ids) - set(request.product_ids))
            num_products = len(filtered_products)
            num_return = min(max_responses, num_products)
            # sample list of indicies to return
            indices = random.sample(range(num_products), num_return)
            # fetch product ids from indices
            prod_list = [filtered_products[i] for i in indices]
            logger.info(
                '[Recv ListRecommendations] product_ids={}'.format(prod_list),
                extra=get_extra_logging_payload())
            # build and return response
        response = demo_pb2.ListRecommendationsResponse()
        response.product_ids.extend(prod_list)
        elasticapm.label(**{'response': MessageToDict(response)})
        elasticapm.set_custom_context({
            'request': request_dict,
            'response': MessageToDict(response)
        })
        client.end_transaction(
            '/hipstershop.RecommendationService/ListRecommendations',
            'success')
        return response
Exemplo n.º 12
0
def test_transaction_max_span_nested(elasticapm_client):
    elasticapm_client.begin_transaction("test_type")
    with elasticapm.capture_span("1"):
        with elasticapm.capture_span("2"):
            with elasticapm.capture_span("3"):
                with elasticapm.capture_span("4"):
                    with elasticapm.capture_span("5"):
                        pass
                with elasticapm.capture_span("6"):
                    pass
            with elasticapm.capture_span("7"):
                pass
        with elasticapm.capture_span("8"):
            pass
    with elasticapm.capture_span("9"):
        pass
    transaction_obj = elasticapm_client.end_transaction("test")

    transaction = elasticapm_client.events[TRANSACTION][0]
    spans = elasticapm_client.events[SPAN]

    assert transaction_obj.dropped_spans == 6
    assert len(spans) == 3
    for span in spans:
        assert span["name"] in ("1", "2", "3")
    assert transaction["span_count"] == {"dropped": 6, "started": 3}
Exemplo n.º 13
0
def test_transaction_max_span_nested(should_collect, elasticapm_client):
    should_collect.return_value = False
    elasticapm_client.begin_transaction("test_type")
    with elasticapm.capture_span("1"):
        with elasticapm.capture_span("2"):
            with elasticapm.capture_span("3"):
                with elasticapm.capture_span("4"):
                    with elasticapm.capture_span("5"):
                        pass
                with elasticapm.capture_span("6"):
                    pass
            with elasticapm.capture_span("7"):
                pass
        with elasticapm.capture_span("8"):
            pass
    with elasticapm.capture_span("9"):
        pass
    transaction_obj = elasticapm_client.end_transaction("test")

    transaction = elasticapm_client.transaction_store.get_all()[0]

    assert transaction_obj.dropped_spans == 6
    assert len(transaction["spans"]) == 3
    for span in transaction["spans"]:
        assert span["name"] in ("1", "2", "3")
    assert transaction["span_count"] == {"dropped": {"total": 6}}
Exemplo n.º 14
0
def test_transaction_max_span_nested(should_collect, elasticapm_client):
    should_collect.return_value = False
    elasticapm_client.begin_transaction('test_type')
    with elasticapm.capture_span('1'):
        with elasticapm.capture_span('2'):
            with elasticapm.capture_span('3'):
                with elasticapm.capture_span('4'):
                    with elasticapm.capture_span('5'):
                        pass
                with elasticapm.capture_span('6'):
                    pass
            with elasticapm.capture_span('7'):
                pass
        with elasticapm.capture_span('8'):
            pass
    with elasticapm.capture_span('9'):
        pass
    transaction_obj = elasticapm_client.end_transaction('test')

    transaction = elasticapm_client.instrumentation_store.get_all()[0]

    assert transaction_obj.dropped_spans == 6
    assert len(transaction['spans']) == 3
    for span in transaction['spans']:
        assert span['name'] in ('1', '2', '3')
    assert transaction['span_count'] == {'dropped': {'total': 6}}
Exemplo n.º 15
0
def get_classroom(url_rid, url_semester):
    """教室查询"""
    from everyclass.server.utils import lesson_string_to_dict
    from everyclass.server.utils import teacher_list_fix
    from everyclass.server.utils import semester_calculate
    from .utils.rpc import HttpRpc

    with elasticapm.capture_span('rpc_query_room'):
        rpc_result = HttpRpc.call_with_error_page('{}/v1/room/{}/{}'.format(
            app.config['API_SERVER_BASE_URL'], url_rid, url_semester),
                                                  params={
                                                      'week_string': 'true',
                                                      'other_semester': 'true'
                                                  },
                                                  retry=True)
        if isinstance(rpc_result, str):
            return rpc_result
        api_response = rpc_result

    if 'name' not in api_response:
        logger.info("Hit classroom 'name' KeyError temporary fix")
        flash("教务数据异常,暂时无法查询本教室。其他教室不受影响。")
        return redirect(url_for("main.main"))

    with elasticapm.capture_span('process_rpc_result'):
        courses = dict()
        for each_class in api_response['course']:
            day, time = lesson_string_to_dict(each_class['lesson'])
            if (day, time) not in courses:
                courses[(day, time)] = list()
            courses[(day, time)].append(
                dict(name=each_class['name'],
                     week=each_class['week_string'],
                     teacher=teacher_list_fix(each_class['teacher']),
                     location=each_class['room'],
                     cid=each_class['cid']))

    empty_5, empty_6, empty_sat, empty_sun = _empty_column_check(courses)

    available_semesters = semester_calculate(
        url_semester, sorted(api_response['semester_list']))

    return render_template('query/room.html',
                           name=api_response['name'],
                           campus=api_response['campus'],
                           building=api_response['building'],
                           rid=url_rid,
                           classes=courses,
                           empty_sat=empty_sat,
                           empty_sun=empty_sun,
                           empty_6=empty_6,
                           empty_5=empty_5,
                           available_semesters=available_semesters,
                           current_semester=url_semester)
Exemplo n.º 16
0
def test_exact_match_after_same_kind(elasticapm_client):
    # if a span that is an exact match is attempted to be compressed with a same_kind composite, it stays same_kind
    transaction = elasticapm_client.begin_transaction("test")
    with elasticapm.capture_span(
            "test1",
            span_type="a",
            span_subtype="b",
            span_action="c",
            leaf=True,
            duration=2,
            extra={"destination": {
                "service": {
                    "resource": "x"
                }
            }},
    ) as span1:
        assert span1.is_compression_eligible()
    with elasticapm.capture_span(
            "test2",
            span_type="a",
            span_subtype="b",
            span_action="c",
            leaf=True,
            duration=3,
            extra={"destination": {
                "service": {
                    "resource": "x"
                }
            }},
    ) as span2:
        assert span2.is_compression_eligible()
        assert not span1.is_exact_match(span2)
        assert span1.is_same_kind(span2)
    with elasticapm.capture_span(
            "test1",
            span_type="a",
            span_subtype="b",
            span_action="c",
            leaf=True,
            duration=2,
            extra={"destination": {
                "service": {
                    "resource": "x"
                }
            }},
    ) as span3:
        assert span3.is_compression_eligible()
    elasticapm_client.end_transaction("test")
    spans = elasticapm_client.events[SPAN]
    assert len(spans) == 1
    span = spans[0]
    assert span["composite"]["compression_strategy"] == "same_kind"
    assert span["composite"]["count"] == 3
Exemplo n.º 17
0
def android_client_get_ics(resource_type, identifier, semester):
    """
    android client get a student or teacher's ics file

    If the student does not have privacy mode, anyone can use student number to subscribe his calendar.
    If the privacy mode is on and there is no HTTP basic authentication, return a 401(unauthorized)
    status code and the Android client ask user for password to try again.
    """
    from flask import current_app as app, redirect, url_for, request

    from everyclass.server.utils.rpc import HttpRpc
    from everyclass.server.db.dao import PrivacySettingsDAO, CalendarTokenDAO, UserDAO

    if resource_type not in ('student', 'teacher'):
        return "Unknown resource type", 400

    with elasticapm.capture_span('rpc_search'):
        rpc_result = HttpRpc.call_with_handle_message('{}/v1/{}/{}/{}'.format(
            app.config['API_SERVER_BASE_URL'], resource_type, identifier,
            semester))
        if isinstance(rpc_result, tuple):
            return rpc_result
        api_response = rpc_result

    if resource_type == 'teacher':
        cal_token = CalendarTokenDAO.get_or_set_calendar_token(
            resource_type=resource_type,
            identifier=rpc_result["sid"],
            semester=semester)
        return redirect(
            url_for('calendar.ics_download', calendar_token=cal_token))
    else:
        # student
        with elasticapm.capture_span('get_privacy_settings'):
            privacy_level = PrivacySettingsDAO.get_level(api_response['sid'])

        # get authorization from HTTP header and verify password if privacy is on
        if privacy_level != 0:
            if not request.authorization:
                return "Unauthorized (privacy on)", 401
            username, password = request.authorization
            if not UserDAO.check_password(username, password):
                return "Unauthorized (password wrong)", 401
            if api_response['sid'] != username:
                return "Unauthorized (username mismatch)", 401

        cal_token = CalendarTokenDAO.get_or_set_calendar_token(
            resource_type=resource_type,
            identifier=rpc_result["sid"],
            semester=semester)
        return redirect(
            url_for('calendar.ics_download', calendar_token=cal_token))
Exemplo n.º 18
0
def get_student(url_sid: str, url_semester: str):
    """学生查询"""
    # decrypt identifier in URL
    try:
        _, student_id = decrypt(url_sid, resource_type='student')
    except ValueError:
        return render_template("common/error.html",
                               message=MSG_INVALID_IDENTIFIER)

    # RPC 获得学生课表
    with elasticapm.capture_span('rpc_get_student_timetable'):
        try:
            student = APIServer.get_student_timetable(student_id, url_semester)
        except Exception as e:
            return handle_exception_with_error_page(e)

    # save sid_orig to session for verifying purpose
    # must be placed before privacy level check. Otherwise a registered user could be redirected to register page.
    session[SESSION_LAST_VIEWED_STUDENT] = StudentSession(
        sid_orig=student.student_id,
        sid=student.student_id_encoded,
        name=student.name)

    # 权限检查,如果没有权限则返回
    has_permission, return_val = check_permission(student)
    if not has_permission:
        return return_val

    with elasticapm.capture_span('process_rpc_result'):
        cards: Dict[Tuple[int, int], List[Dict[str, str]]] = dict()
        for card in student.cards:
            day, time = lesson_string_to_tuple(card.lesson)
            if (day, time) not in cards:
                cards[(day, time)] = list()
            cards[(day, time)].append(card)
        empty_5, empty_6, empty_sat, empty_sun = _empty_column_check(cards)
        available_semesters = semester_calculate(url_semester,
                                                 sorted(student.semesters))

    # 增加访客记录
    Redis.add_visitor_count(student.student_id,
                            session.get(SESSION_CURRENT_USER, None))

    return render_template('query/student.html',
                           student=student,
                           cards=cards,
                           empty_sat=empty_sat,
                           empty_sun=empty_sun,
                           empty_6=empty_6,
                           empty_5=empty_5,
                           available_semesters=available_semesters,
                           current_semester=url_semester)
Exemplo n.º 19
0
def legacy_get_ics(student_id, semester_str):
    """
    legacy iCalendar endpoint

    query the student first, if the student is not privacy protected, redirect to new ics. else return 401.

    this route is bad. however, many users have already been using it. breaking experience is bad. so we have
    to keep the route here for now. and (maybe) remove it in the future.
    """
    from flask import current_app as app, abort, redirect, url_for

    from everyclass.server.db.dao import PrivacySettingsDAO, CalendarTokenDAO
    from everyclass.server.utils.rpc import HttpRpc
    from everyclass.server.db.model import Semester

    # fix parameters
    place = student_id.find('-')
    semester_str = student_id[place + 1:len(student_id)] + '-' + semester_str
    student_id = student_id[:place]

    semester = Semester(semester_str)

    with elasticapm.capture_span('rpc_search'):
        rpc_result = HttpRpc.call_with_error_page('{}/v1/search/{}'.format(
            app.config['API_SERVER_BASE_URL'], student_id),
                                                  retry=True)
        if isinstance(rpc_result, str):
            return rpc_result
        api_response = rpc_result

    if len(api_response['student']) != 1:
        # bad request
        return abort(400)

    if semester.to_str() not in api_response['student'][0]['semester']:
        return abort(400)

    with elasticapm.capture_span('get_privacy_settings'):
        privacy_settings = PrivacySettingsDAO.get_level(
            api_response['student'][0]['sid_orig'])

    if privacy_settings != 0:
        # force user to get a calendar token when the user is privacy-protected but accessed through legacy interface
        return "Visit {} to get your calendar".format(
            url_for("main.main")), 401
    else:
        token = CalendarTokenDAO.get_or_set_calendar_token(
            resource_type="student",
            identifier=api_response['student'][0]['sid_orig'],
            semester=semester.to_str())
        return redirect(url_for('calendar.ics_download', calendar_token=token))
Exemplo n.º 20
0
def test_outcome_by_span_exception(elasticapm_client):
    elasticapm_client.begin_transaction("test")
    try:
        with elasticapm.capture_span("fail", "test_type"):
            assert False
    except AssertionError:
        pass
    with elasticapm.capture_span("success", "test_type"):
        pass
    elasticapm_client.end_transaction("test")
    transactions = elasticapm_client.events[TRANSACTION]
    spans = elasticapm_client.spans_for_transaction(transactions[0])
    assert spans[0]["name"] == "fail" and spans[0]["outcome"] == "failure"
    assert spans[1]["name"] == "success" and spans[1]["outcome"] == "success"
Exemplo n.º 21
0
def get_teacher(url_tid, url_semester):
    """老师查询"""
    from everyclass.server.utils import lesson_string_to_dict
    from everyclass.server.utils import semester_calculate
    from .utils.rpc import HttpRpc

    with elasticapm.capture_span('rpc_query_student'):
        rpc_result = HttpRpc.call_with_error_page('{}/v1/teacher/{}/{}'.format(
            app.config['API_SERVER_BASE_URL'], url_tid, url_semester),
                                                  params={
                                                      'week_string': 'true',
                                                      'other_semester': 'true'
                                                  },
                                                  retry=True)
        if isinstance(rpc_result, str):
            return rpc_result
        api_response = rpc_result

    with elasticapm.capture_span('process_rpc_result'):
        courses = dict()
        for each_class in api_response['course']:
            day, time = lesson_string_to_dict(each_class['lesson'])
            if (day, time) not in courses:
                courses[(day, time)] = list()
            courses[(day, time)].append(
                dict(name=each_class['name'],
                     week=each_class['week_string'],
                     classroom=each_class['room'],
                     classroom_id=each_class['rid'],
                     cid=each_class['cid']))

    empty_5, empty_6, empty_sat, empty_sun = _empty_column_check(courses)

    available_semesters = semester_calculate(
        url_semester, sorted(api_response['semester_list']))

    return render_template('query/teacher.html',
                           name=api_response['name'],
                           falculty=api_response['unit'],
                           title=api_response['title'],
                           tid=url_tid,
                           classes=courses,
                           empty_sat=empty_sat,
                           empty_sun=empty_sun,
                           empty_6=empty_6,
                           empty_5=empty_5,
                           available_semesters=available_semesters,
                           current_semester=url_semester)
Exemplo n.º 22
0
def test_transaction_span_frames_min_duration(elasticapm_client):
    elasticapm_client.begin_transaction("test_type")
    with elasticapm.capture_span("noframes", duration=0.001):
        pass
    with elasticapm.capture_span("frames", duration=0.04):
        pass
    elasticapm_client.end_transaction("test")

    spans = elasticapm_client.events[SPAN]

    assert len(spans) == 2
    assert spans[0]["name"] == "noframes"
    assert "stacktrace" not in spans[0]

    assert spans[1]["name"] == "frames"
    assert spans[1]["stacktrace"] is not None
Exemplo n.º 23
0
def test_transaction_keyword_truncation(sending_elasticapm_client):
    too_long = 'x' * (KEYWORD_MAX_LENGTH + 1)
    expected = encoding.keyword_field(too_long)
    assert too_long != expected
    assert len(expected) == KEYWORD_MAX_LENGTH
    assert expected[-1] != 'x'
    sending_elasticapm_client.begin_transaction(too_long)
    elasticapm.tag(val=too_long)
    elasticapm.set_user_context(username=too_long, email=too_long, user_id=too_long)
    with elasticapm.capture_span(name=too_long, span_type=too_long):
        pass
    sending_elasticapm_client.end_transaction(too_long, too_long)
    sending_elasticapm_client.close()
    assert sending_elasticapm_client.httpserver.responses[0]['code'] == 202
    transaction = sending_elasticapm_client.httpserver.payloads[0]['transactions'][0]
    span = transaction['spans'][0]

    assert transaction['name'] == expected
    assert transaction['type'] == expected
    assert transaction['result'] == expected

    assert transaction['context']['user']['id'] == expected
    assert transaction['context']['user']['username'] == expected
    assert transaction['context']['user']['email'] == expected

    assert transaction['context']['tags']['val'] == expected

    assert span['type'] == expected
    assert span['name'] == expected
Exemplo n.º 24
0
def get_card(url_cid: str, url_semester: str):
    """课程查询"""
    # decrypt identifier in URL
    try:
        _, card_id = decrypt(url_cid, resource_type='klass')
    except ValueError:
        return render_template("common/error.html",
                               message=MSG_INVALID_IDENTIFIER)

    # RPC to get card
    with elasticapm.capture_span('rpc_get_card'):
        try:
            card = APIServer.get_card(url_semester, card_id)
        except Exception as e:
            return handle_exception_with_error_page(e)

    day, time = lesson_string_to_tuple(card.lesson)

    # 给“文化素质类”等加上“课”后缀
    if card.type and card.type[-1] != '课':
        card.type = card.type + '课'

    cotc_id = COTeachingClass.get_id_by_card(card)
    course_review_doc = CourseReview.get_review(cotc_id)

    return render_template(
        'query/card.html',
        card=card,
        card_day=get_day_chinese(day),
        card_time=get_time_chinese(time),
        show_union_class=not card.union_name.isdigit(),  # 合班名称为数字时不展示合班名称
        cotc_id=cotc_id,
        cotc_rating=course_review_doc["avg_rate"],
        current_semester=url_semester)
Exemplo n.º 25
0
def test_collect_source_transactions(should_collect, elasticapm_client):
    should_collect.return_value = False
    library_frame_context = elasticapm_client.config.source_lines_span_library_frames
    in_app_frame_context = elasticapm_client.config.source_lines_span_app_frames
    elasticapm_client.begin_transaction('test')
    with elasticapm.capture_span('foo'):
        pass
    elasticapm_client.end_transaction('test', 'ok')
    transaction = elasticapm_client.instrumentation_store.get_all()[0]
    in_app_frame = transaction['spans'][0]['stacktrace'][0]
    library_frame = transaction['spans'][0]['stacktrace'][1]
    assert not in_app_frame['library_frame']
    assert library_frame['library_frame']
    if library_frame_context:
        assert 'context_line' in library_frame, library_frame_context
        assert 'pre_context' in library_frame, library_frame_context
        assert 'post_context' in library_frame, library_frame_context
        lines = len([library_frame['context_line']] + library_frame['pre_context'] + library_frame['post_context'])
        assert lines == library_frame_context, library_frame_context
    else:
        assert 'context_line' not in library_frame, library_frame_context
        assert 'pre_context' not in library_frame, library_frame_context
        assert 'post_context' not in library_frame, library_frame_context
    if in_app_frame_context:
        assert 'context_line' in in_app_frame, in_app_frame_context
        assert 'pre_context' in in_app_frame, in_app_frame_context
        assert 'post_context' in in_app_frame, in_app_frame_context
        lines = len([in_app_frame['context_line']] + in_app_frame['pre_context'] + in_app_frame['post_context'])
        assert lines == in_app_frame_context, (in_app_frame_context, in_app_frame['lineno'])
    else:
        assert 'context_line' not in in_app_frame, in_app_frame_context
        assert 'pre_context' not in in_app_frame, in_app_frame_context
        assert 'post_context' not in in_app_frame, in_app_frame_context
Exemplo n.º 26
0
def test_skip_ignored_frames(elasticapm_client):
    elasticapm_client.begin_transaction('test')
    with elasticapm.capture_span('test'):
        pass
    transaction = elasticapm_client.end_transaction('test', 'test')
    for frame in transaction.spans[0].frames:
        assert not frame['module'].startswith('elasticapm')
Exemplo n.º 27
0
def test_collect_source_transactions(elasticapm_client):
    library_frame_context = elasticapm_client.config.source_lines_span_library_frames
    in_app_frame_context = elasticapm_client.config.source_lines_span_app_frames
    elasticapm_client.begin_transaction("test")
    with elasticapm.capture_span("foo"):
        pass
    elasticapm_client.end_transaction("test", "ok")
    span = elasticapm_client.events[SPAN][0]
    in_app_frame = span["stacktrace"][0]
    library_frame = span["stacktrace"][1]
    assert not in_app_frame["library_frame"]
    assert library_frame["library_frame"]
    if library_frame_context:
        assert "context_line" in library_frame, library_frame_context
        assert "pre_context" in library_frame, library_frame_context
        assert "post_context" in library_frame, library_frame_context
        lines = len([library_frame["context_line"]] + library_frame["pre_context"] + library_frame["post_context"])
        assert lines == library_frame_context, library_frame_context
    else:
        assert "context_line" not in library_frame, library_frame_context
        assert "pre_context" not in library_frame, library_frame_context
        assert "post_context" not in library_frame, library_frame_context
    if in_app_frame_context:
        assert "context_line" in in_app_frame, in_app_frame_context
        assert "pre_context" in in_app_frame, in_app_frame_context
        assert "post_context" in in_app_frame, in_app_frame_context
        lines = len([in_app_frame["context_line"]] + in_app_frame["pre_context"] + in_app_frame["post_context"])
        assert lines == in_app_frame_context, (in_app_frame_context, in_app_frame["lineno"])
    else:
        assert "context_line" not in in_app_frame, in_app_frame_context
        assert "pre_context" not in in_app_frame, in_app_frame_context
        assert "post_context" not in in_app_frame, in_app_frame_context
Exemplo n.º 28
0
    def call(self, module, method, wrapped, instance, args, kwargs):
        args_len = len(args)
        http_method = args[0] if args_len else kwargs.get("method")
        http_path = args[1] if args_len > 1 else kwargs.get("url")
        params = args[2] if args_len > 2 else kwargs.get("params")
        body = params.pop(BODY_REF_NAME, None) if params else None

        api_method = params.pop(API_METHOD_KEY_NAME, None) if params else None

        signature = "ES %s %s" % (http_method, http_path)
        context = {"db": {"type": "elasticsearch"}}
        if api_method in self.query_methods:
            query = []
            # using both q AND body is allowed in some API endpoints / ES versions,
            # but not in others. We simply capture both if they are there so the
            # user can see it.
            if params and "q" in params:
                # 'q' is already encoded to a byte string at this point
                # we assume utf8, which is the default
                query.append("q=" + params["q"].decode("utf-8", errors="replace"))
            if isinstance(body, dict) and "query" in body:
                query.append(json.dumps(body["query"], default=compat.text_type))
            context["db"]["statement"] = "\n\n".join(query)
        elif api_method == "Elasticsearch.update":
            if isinstance(body, dict) and "script" in body:
                # only get the `script` field from the body
                context["db"]["statement"] = json.dumps({"script": body["script"]})
        # TODO: add instance.base_url to context once we agreed on a format
        with elasticapm.capture_span(signature, "db.elasticsearch", extra=context, skip_frames=2, leaf=True):
            return wrapped(*args, **kwargs)
Exemplo n.º 29
0
def test_transaction_keyword_truncation(elasticapm_client):
    too_long = "x" * (KEYWORD_MAX_LENGTH + 1)
    expected = encoding.keyword_field(too_long)
    assert too_long != expected
    assert len(expected) == KEYWORD_MAX_LENGTH
    assert expected[-1] != "x"
    elasticapm_client.begin_transaction(too_long)
    elasticapm.tag(val=too_long)
    elasticapm.set_user_context(username=too_long, email=too_long, user_id=too_long)
    with elasticapm.capture_span(name=too_long, span_type=too_long):
        pass
    elasticapm_client.end_transaction(too_long, too_long)
    elasticapm_client.close()

    span = elasticapm_client.events["span"][0]
    transaction = elasticapm_client.events["transaction"][0]

    assert transaction["name"] == expected
    assert transaction["type"] == expected
    assert transaction["result"] == expected

    assert transaction["context"]["user"]["id"] == expected
    assert transaction["context"]["user"]["username"] == expected
    assert transaction["context"]["user"]["email"] == expected

    assert transaction["context"]["tags"]["val"] == expected

    assert span["type"] == expected
    assert span["name"] == expected
Exemplo n.º 30
0
def test_transaction_span_frames_min_duration_no_limit(elasticapm_client):
    elasticapm_client.begin_transaction("test_type")
    with elasticapm.capture_span("frames"):
        pass
    with elasticapm.capture_span("frames"):
        time.sleep(0.040)
    elasticapm_client.end_transaction("test")

    spans = elasticapm_client.events[SPAN]

    assert len(spans) == 2
    assert spans[0]["name"] == "frames"
    assert spans[0]["stacktrace"] is not None

    assert spans[1]["name"] == "frames"
    assert spans[1]["stacktrace"] is not None