xref: /aosp_15_r20/external/autotest/client/cros/cellular/pseudomodem/utils.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li#!/usr/bin/env python
2*9c5db199SXin Li
3*9c5db199SXin Li# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
4*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
5*9c5db199SXin Li# found in the LICENSE file.
6*9c5db199SXin Li
7*9c5db199SXin Liimport functools
8*9c5db199SXin Liimport inspect
9*9c5db199SXin Liimport logging
10*9c5db199SXin Liimport traceback
11*9c5db199SXin Li
12*9c5db199SXin Lidef log_dbus_method(return_logger=logging.debug, raise_logger=logging.warning,
13*9c5db199SXin Li                    return_cb_arg=None, raise_cb_arg=None):
14*9c5db199SXin Li    """
15*9c5db199SXin Li    Factory method for decorator to log dbus responses / errors.
16*9c5db199SXin Li
17*9c5db199SXin Li    This method should be used to decorate the most concerete implementation of
18*9c5db199SXin Li    a dbus method.
19*9c5db199SXin Li
20*9c5db199SXin Li    @param return_logger: A function that accepts a string argument to log the
21*9c5db199SXin Li            response from the decorated function.
22*9c5db199SXin Li    @param raise_logger: A function accepts a string argument to log the
23*9c5db199SXin Li            exception raised by the decorated function.
24*9c5db199SXin Li    @param return_cb_arg: str name of the async callback argument for the return
25*9c5db199SXin Li            value, if the function takes one.
26*9c5db199SXin Li    @param raise_cb_arg: str name of the async callback argument for the error
27*9c5db199SXin Li            return value, if the function takes one.
28*9c5db199SXin Li
29*9c5db199SXin Li    """
30*9c5db199SXin Li    def wrapper(func):
31*9c5db199SXin Li        """
32*9c5db199SXin Li        The decorator returned by this factory.
33*9c5db199SXin Li
34*9c5db199SXin Li        @param func: The function to be decorated.
35*9c5db199SXin Li
36*9c5db199SXin Li        """
37*9c5db199SXin Li        @functools.wraps(func)
38*9c5db199SXin Li        def wrapped_func(*args, **kwargs):
39*9c5db199SXin Li            """The modified function for the decorated function."""
40*9c5db199SXin Li            modified_args = list(args)
41*9c5db199SXin Li            modified_kwargs = kwargs
42*9c5db199SXin Li            return_cb_index = getattr(wrapped_func, '_logging_return_cb_index')
43*9c5db199SXin Li            if return_cb_index > -1:
44*9c5db199SXin Li                if len(args) > return_cb_index:
45*9c5db199SXin Li                    modified_args[return_cb_index] = _wrap_async_return(
46*9c5db199SXin Li                            args[return_cb_index],
47*9c5db199SXin Li                            func.__name__,
48*9c5db199SXin Li                            return_logger)
49*9c5db199SXin Li                elif return_cb_arg in kwargs:
50*9c5db199SXin Li                    modified_kwargs[return_cb_arg] = _wrap_async_return(
51*9c5db199SXin Li                            kwargs[return_cb_arg],
52*9c5db199SXin Li                            func.__name__,
53*9c5db199SXin Li                            return_logger)
54*9c5db199SXin Li                else:
55*9c5db199SXin Li                    logging.debug('Not logging default return_cb')
56*9c5db199SXin Li
57*9c5db199SXin Li            raise_cb_index = getattr(wrapped_func, '_logging_raise_cb_index')
58*9c5db199SXin Li            if raise_cb_index > -1:
59*9c5db199SXin Li                if len(args) > raise_cb_index:
60*9c5db199SXin Li                    modified_args[raise_cb_index] = _wrap_async_raise(
61*9c5db199SXin Li                            args[raise_cb_index],
62*9c5db199SXin Li                            func.__name__,
63*9c5db199SXin Li                            raise_logger)
64*9c5db199SXin Li                elif raise_cb_arg in kwargs:
65*9c5db199SXin Li                    modified_kwargs[raise_cb_arg] = _wrap_async_raise(
66*9c5db199SXin Li                            kwargs[raise_cb_arg],
67*9c5db199SXin Li                            func.__name__,
68*9c5db199SXin Li                            raise_logger)
69*9c5db199SXin Li                else:
70*9c5db199SXin Li                    logging.debug('Not logging default raise_cb')
71*9c5db199SXin Li
72*9c5db199SXin Li            try:
73*9c5db199SXin Li                retval = func(*modified_args, **modified_kwargs)
74*9c5db199SXin Li                # No |return_cb_arg| ==> return value is the DBus response, so
75*9c5db199SXin Li                # it needs to be logged.
76*9c5db199SXin Li                if return_cb_index == -1:
77*9c5db199SXin Li                    return_logger('Response[%s] OK: |%s|' % (func.__name__,
78*9c5db199SXin Li                                                             repr(retval)))
79*9c5db199SXin Li            except Exception as e:
80*9c5db199SXin Li                raise_logger('Response[%s] ERROR: |%s|' % (func.__name__,
81*9c5db199SXin Li                                                           repr(e)))
82*9c5db199SXin Li                raise_logger(traceback.format_exc())
83*9c5db199SXin Li                raise
84*9c5db199SXin Li            return retval
85*9c5db199SXin Li
86*9c5db199SXin Li
87*9c5db199SXin Li        args, _, _, defaults = inspect.getargspec(func)
88*9c5db199SXin Li        wrapped_func._logging_return_cb_index = -1
89*9c5db199SXin Li        wrapped_func._logging_raise_cb_index = -1
90*9c5db199SXin Li        if return_cb_arg:
91*9c5db199SXin Li            if return_cb_arg not in args:
92*9c5db199SXin Li                logging.warning(
93*9c5db199SXin Li                        'Did not find expected argument %s in argument list '
94*9c5db199SXin Li                        'of %s', return_cb_arg, func.__name__)
95*9c5db199SXin Li            wrapped_func._logging_return_cb_index = args.index(return_cb_arg)
96*9c5db199SXin Li        if raise_cb_arg:
97*9c5db199SXin Li            if raise_cb_arg not in args:
98*9c5db199SXin Li                logging.warning(
99*9c5db199SXin Li                        'Did not find expected argument %s in argument list '
100*9c5db199SXin Li                        'of %s', raise_cb_arg, func.__name__)
101*9c5db199SXin Li            wrapped_func._logging_raise_cb_index = args.index(raise_cb_arg)
102*9c5db199SXin Li        return wrapped_func
103*9c5db199SXin Li    return wrapper
104*9c5db199SXin Li
105*9c5db199SXin Li
106*9c5db199SXin Lidef _wrap_async_return(return_cb, fname, logger):
107*9c5db199SXin Li    """
108*9c5db199SXin Li    Wrap return_cb to log the return value.
109*9c5db199SXin Li
110*9c5db199SXin Li    @param return_cb: The function to be wrapped.
111*9c5db199SXin Li    @param fname: Name of the DBus function called.
112*9c5db199SXin Li    @param logger: The logger to use for logging.
113*9c5db199SXin Li    @returns: Wrapped |return_cb| that additionally logs its arguments.
114*9c5db199SXin Li
115*9c5db199SXin Li    """
116*9c5db199SXin Li    @functools.wraps(return_cb)
117*9c5db199SXin Li    def wrapped_return_cb(*args, **kwargs):
118*9c5db199SXin Li        """ Log arguments before calling return_cb. """
119*9c5db199SXin Li        logger('AsyncResponse[%s] OK: |%s|' % (fname, str((args, kwargs))))
120*9c5db199SXin Li        return_cb(*args, **kwargs)
121*9c5db199SXin Li
122*9c5db199SXin Li    return wrapped_return_cb
123*9c5db199SXin Li
124*9c5db199SXin Li
125*9c5db199SXin Lidef _wrap_async_raise(raise_cb, fname, logger):
126*9c5db199SXin Li    """
127*9c5db199SXin Li    Wrap raise_cb to log the raised error.
128*9c5db199SXin Li
129*9c5db199SXin Li    @param raise_cb: The function to be wrapped.
130*9c5db199SXin Li    @param fname: Name of the DBus function called.
131*9c5db199SXin Li    @param logger: The logger to use for logging.
132*9c5db199SXin Li    @returns: Wrapped |raise_cb| that additionally logs its arguments.
133*9c5db199SXin Li
134*9c5db199SXin Li    """
135*9c5db199SXin Li    @functools.wraps(raise_cb)
136*9c5db199SXin Li    def wrapped_raise_cb(*args, **kwargs):
137*9c5db199SXin Li        """ Log arguments before calling raise_cb. """
138*9c5db199SXin Li        logger('AsyncResponse[%s] ERROR: |%s|' % (fname, str((args, kwargs))))
139*9c5db199SXin Li        logger(traceback.format_exc())
140*9c5db199SXin Li        raise_cb(*args, **kwargs)
141*9c5db199SXin Li
142*9c5db199SXin Li    return wrapped_raise_cb
143